33c0aa2a8d658887c8c4c3eb58322e3556e3b253
[pintos-anon] / solutions / p4.patch
1 Index: src/Makefile.build
2 diff -u src/Makefile.build~ src/Makefile.build
3 --- src/Makefile.build~
4 +++ src/Makefile.build
5 @@ -53,7 +53,9 @@ userprog_SRC += userprog/gdt.c                # GDT in
6  userprog_SRC += userprog/tss.c         # TSS management.
7  
8  # No virtual memory code yet.
9 -#vm_SRC = vm/file.c                    # Some file.
10 +vm_SRC = vm/page.c
11 +vm_SRC += vm/frame.c
12 +vm_SRC += vm/swap.c
13  
14  # Filesystem code.
15  filesys_SRC  = filesys/filesys.c       # Filesystem core.
16 @@ -62,6 +64,7 @@ filesys_SRC += filesys/file.c         # Files.
17  filesys_SRC += filesys/directory.c     # Directories.
18  filesys_SRC += filesys/inode.c         # File headers.
19  filesys_SRC += filesys/fsutil.c                # Utilities.
20 +filesys_SRC += filesys/cache.c         # Cache.
21  
22  SOURCES = $(foreach dir,$(KERNEL_SUBDIRS),$($(dir)_SRC))
23  OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES)))
24 Index: src/devices/timer.c
25 diff -u src/devices/timer.c~ src/devices/timer.c
26 --- src/devices/timer.c~
27 +++ src/devices/timer.c
28 @@ -23,6 +23,9 @@ static volatile int64_t ticks;
29     Initialized by timer_calibrate(). */
30  static unsigned loops_per_tick;
31  
32 +/* Threads waiting in timer_sleep(). */
33 +static struct list wait_list;
34 +
35  static intr_handler_func timer_interrupt;
36  static bool too_many_loops (unsigned loops);
37  static void busy_wait (int64_t loops);
38 @@ -43,6 +46,8 @@ timer_init (void) 
39    outb (0x40, count >> 8);
40  
41    intr_register_ext (0x20, timer_interrupt, "8254 Timer");
42 +
43 +  list_init (&wait_list);
44  }
45  
46  /* Calibrates loops_per_tick, used to implement brief delays. */
47 @@ -87,15 +92,36 @@ timer_elapsed (int64_t then) 
48    return timer_ticks () - then;
49  }
50  
51 +/* Compares two threads based on their wake-up times. */
52 +static bool
53 +compare_threads_by_wakeup_time (const struct list_elem *a_,
54 +                                const struct list_elem *b_,
55 +                                void *aux UNUSED) 
56 +{
57 +  const struct thread *a = list_entry (a_, struct thread, timer_elem);
58 +  const struct thread *b = list_entry (b_, struct thread, timer_elem);
59 +
60 +  return a->wakeup_time < b->wakeup_time;
61 +}
62 +
63  /* Suspends execution for approximately TICKS timer ticks. */
64  void
65  timer_sleep (int64_t ticks) 
66  {
67 -  int64_t start = timer_ticks ();
68 +  struct thread *t = thread_current ();
69 +
70 +  /* Schedule our wake-up time. */
71 +  t->wakeup_time = timer_ticks () + ticks;
72  
73 +  /* Atomically insert the current thread into the wait list. */
74    ASSERT (intr_get_level () == INTR_ON);
75 -  while (timer_elapsed (start) < ticks) 
76 -    thread_yield ();
77 +  intr_disable ();
78 +  list_insert_ordered (&wait_list, &t->timer_elem,
79 +                       compare_threads_by_wakeup_time, NULL);
80 +  intr_enable ();
81 +
82 +  /* Wait. */
83 +  sema_down (&t->timer_sema);
84  }
85  
86  /* Suspends execution for approximately MS milliseconds. */
87 @@ -132,6 +158,16 @@ timer_interrupt (struct intr_frame *args
88  {
89    ticks++;
90    thread_tick ();
91 +
92 +  while (!list_empty (&wait_list))
93 +    {
94 +      struct thread *t = list_entry (list_front (&wait_list),
95 +                                     struct thread, timer_elem);
96 +      if (ticks < t->wakeup_time) 
97 +        break;
98 +      sema_up (&t->timer_sema);
99 +      list_pop_front (&wait_list);
100 +    }
101  }
102  
103  /* Returns true if LOOPS iterations waits for more than one timer
104 Index: src/filesys/Make.vars
105 diff -u src/filesys/Make.vars~ src/filesys/Make.vars
106 --- src/filesys/Make.vars~
107 +++ src/filesys/Make.vars
108 @@ -6,7 +6,7 @@ TEST_SUBDIRS = tests/userprog tests/file
109  GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.no-vm
110  
111  # Uncomment the lines below to enable VM.
112 -#os.dsk: DEFINES += -DVM
113 -#KERNEL_SUBDIRS += vm
114 -#TEST_SUBDIRS += tests/vm
115 -#GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.with-vm
116 +os.dsk: DEFINES += -DVM
117 +KERNEL_SUBDIRS += vm
118 +TEST_SUBDIRS += tests/vm
119 +GRADING_FILE = $(SRCDIR)/tests/filesys/Grading.with-vm
120 Index: src/filesys/cache.c
121 diff -u src/filesys/cache.c~ src/filesys/cache.c
122 --- src/filesys/cache.c~
123 +++ src/filesys/cache.c
124 @@ -0,0 +1,473 @@
125 +#include "filesys/cache.h"
126 +#include <debug.h>
127 +#include <string.h>
128 +#include "filesys/filesys.h"
129 +#include "devices/disk.h"
130 +#include "devices/timer.h"
131 +#include "threads/malloc.h"
132 +#include "threads/synch.h"
133 +#include "threads/thread.h"
134 +
135 +#define INVALID_SECTOR ((disk_sector_t) -1)
136 +
137 +/* A cached block. */
138 +struct cache_block 
139 +  {
140 +    /* Locking to prevent eviction. */
141 +    struct lock block_lock;                    /* Protects fields in group. */
142 +    struct condition no_readers_or_writers; /* readers == 0 && writers == 0 */
143 +    struct condition no_writers;                            /* writers == 0 */
144 +    int readers, read_waiters;          /* # of readers, # waiting to read. */
145 +    int writers, write_waiters; /* # of writers (<= 1), # waiting to write. */
146 +
147 +    /* Sector number.  INVALID_SECTOR indicates a free cache block.
148 +
149 +       Changing from free to allocated requires cache_sync.
150 +
151 +       Changing from allocated to free requires block_lock, block
152 +       must be up-to-date and not dirty, and no one may be
153 +       waiting on it. */
154 +    disk_sector_t sector;
155 +
156 +    /* Is data[] correct?
157 +       Requires write lock or data_lock. */
158 +    bool up_to_date;
159 +
160 +    /* Does data[] need to be written back to disk?
161 +       Valid only when up-to-date.
162 +       Requires read lock or write lock or data_lock. */
163 +    bool dirty;
164 +
165 +    /* Sector data.
166 +       Access to data[] requires up-to-date and read or write lock.
167 +       Bringing up-to-date requires write lock or data_lock. */
168 +    struct lock data_lock;              /* Protects fields in group. */
169 +    uint8_t data[DISK_SECTOR_SIZE];     /* Disk data. */
170 +  };
171 +
172 +/* Cache. */
173 +#define CACHE_CNT 64
174 +struct cache_block cache[CACHE_CNT];
175 +
176 +/* Cache lock.
177 +
178 +   Required to allocate a cache block to a sector, to prevent a
179 +   single sector being allocated two different cache blocks.
180 +
181 +   Required to search the cache for a sector, to prevent the
182 +   sector from being added while the search is ongoing.
183 +
184 +   Protects hand. */
185 +struct lock cache_sync;
186 +
187 +/* Cache eviction hand.
188 +   Protected by cache_sync. */
189 +static int hand = 0;
190 +
191 +static void flushd_init (void);
192 +static void readaheadd_init (void);
193 +static void readaheadd_submit (disk_sector_t sector);
194 +\f
195 +/* Initializes cache. */
196 +void
197 +cache_init (void) 
198 +{
199 +  int i;
200 +  
201 +  lock_init (&cache_sync);
202 +  for (i = 0; i < CACHE_CNT; i++) 
203 +    {
204 +      struct cache_block *b = &cache[i];
205 +      lock_init (&b->block_lock);
206 +      cond_init (&b->no_readers_or_writers);
207 +      cond_init (&b->no_writers);
208 +      b->readers = b->read_waiters = 0;
209 +      b->writers = b->write_waiters = 0;
210 +      b->sector = INVALID_SECTOR;
211 +      lock_init (&b->data_lock);
212 +    }
213 +
214 +  flushd_init ();
215 +  readaheadd_init ();
216 +}
217 +
218 +/* Flushes cache to disk. */
219 +void
220 +cache_flush (void) 
221 +{
222 +  int i;
223 +  
224 +  for (i = 0; i < CACHE_CNT; i++)
225 +    {
226 +      struct cache_block *b = &cache[i];
227 +      disk_sector_t sector;
228 +      
229 +      lock_acquire (&b->block_lock);
230 +      sector = b->sector;
231 +      lock_release (&b->block_lock);
232 +
233 +      if (sector == INVALID_SECTOR)
234 +        continue;
235 +
236 +      b = cache_lock (sector, EXCLUSIVE);
237 +      if (b->up_to_date && b->dirty) 
238 +        {
239 +          disk_write (filesys_disk, b->sector, b->data);
240 +          b->dirty = false; 
241 +        }
242 +      cache_unlock (b);
243 +    }
244 +}
245 +
246 +/* Locks the given SECTOR into the cache and returns the cache
247 +   block.
248 +   If TYPE is EXCLUSIVE, then the block returned will be locked
249 +   only by the caller.  The calling thread must not already
250 +   have any lock on the block.
251 +   If TYPE is NON_EXCLUSIVE, then block returned may be locked by
252 +   any number of other callers.  The calling thread may already
253 +   have any number of non-exclusive locks on the block. */
254 +struct cache_block *
255 +cache_lock (disk_sector_t sector, enum lock_type type) 
256 +{
257 +  int i;
258 +
259 + try_again:
260 +  lock_acquire (&cache_sync);
261 +
262 +  /* Is the block already in-cache? */
263 +  for (i = 0; i < CACHE_CNT; i++)
264 +    {
265 +      /* Skip any blocks that don't hold SECTOR. */
266 +      struct cache_block *b = &cache[i];
267 +      lock_acquire (&b->block_lock);
268 +      if (b->sector != sector) 
269 +        {
270 +          lock_release (&b->block_lock);
271 +          continue;
272 +        }
273 +      lock_release (&cache_sync);
274 +
275 +      /* Get read or write lock. */
276 +      if (type == NON_EXCLUSIVE) 
277 +        {
278 +          /* Lock for read. */
279 +          b->read_waiters++;
280 +          if (b->writers || b->write_waiters)
281 +            do {
282 +              cond_wait (&b->no_writers, &b->block_lock);
283 +            } while (b->writers);
284 +          b->readers++;
285 +          b->read_waiters--;
286 +        }
287 +      else 
288 +        {
289 +          /* Lock for write. */
290 +          b->write_waiters++;
291 +          if (b->readers || b->read_waiters || b->writers)
292 +            do {
293 +              cond_wait (&b->no_readers_or_writers, &b->block_lock);
294 +            } while (b->readers || b->writers);
295 +          b->writers++;
296 +          b->write_waiters--;
297 +        }
298 +      lock_release (&b->block_lock);
299 +
300 +      /* Our sector should have been pinned in the cache while we
301 +         were waiting.  Make sure. */
302 +      ASSERT (b->sector == sector);
303 +
304 +      return b;
305 +    }
306 +
307 +  /* Not in cache.  Find empty slot.
308 +     We hold cache_sync. */
309 +  for (i = 0; i < CACHE_CNT; i++)
310 +    {
311 +      struct cache_block *b = &cache[i];
312 +      lock_acquire (&b->block_lock);
313 +      if (b->sector == INVALID_SECTOR) 
314 +        {
315 +          /* Drop block_lock, which is no longer needed because
316 +             this is the only code that allocates free blocks,
317 +             and we still have cache_sync.
318 +
319 +             We can't drop cache_sync yet because someone else
320 +             might try to allocate this same block (or read from
321 +             it) while we're still initializing the block. */
322 +          lock_release (&b->block_lock);
323 +
324 +          b->sector = sector;
325 +          b->up_to_date = false;
326 +          ASSERT (b->readers == 0);
327 +          ASSERT (b->writers == 0);
328 +          if (type == NON_EXCLUSIVE)
329 +            b->readers = 1;
330 +          else
331 +            b->writers = 1;
332 +          lock_release (&cache_sync);
333 +          return b;
334 +        }
335 +      lock_release (&b->block_lock); 
336 +    }
337 +
338 +  /* No empty slots.  Evict something.
339 +     We hold cache_sync. */
340 +  for (i = 0; i < CACHE_CNT; i++)
341 +    {
342 +      struct cache_block *b = &cache[hand];
343 +      if (++hand >= CACHE_CNT)
344 +        hand = 0;
345 +
346 +      /* Try to grab exclusive write access to block. */
347 +      lock_acquire (&b->block_lock);
348 +      if (b->readers || b->writers || b->read_waiters || b->write_waiters) 
349 +        {
350 +          lock_release (&b->block_lock);
351 +          continue;
352 +        }
353 +      b->writers = 1;
354 +      lock_release (&b->block_lock);
355 +
356 +      lock_release (&cache_sync);
357 +
358 +      /* Write block to disk if dirty. */
359 +      if (b->up_to_date && b->dirty) 
360 +        {
361 +          disk_write (filesys_disk, b->sector, b->data);
362 +          b->dirty = false;
363 +        }
364 +
365 +      /* Remove block from cache, if possible: someone might have
366 +         started waiting on it while the lock was released. */
367 +      lock_acquire (&b->block_lock);
368 +      b->writers = 0;
369 +      if (!b->read_waiters && !b->write_waiters) 
370 +        {
371 +          /* No one is waiting for it, so we can free it. */
372 +          b->sector = INVALID_SECTOR; 
373 +        }
374 +      else 
375 +        {
376 +          /* There is a waiter.  Give it the block. */
377 +          if (b->read_waiters)
378 +            cond_broadcast (&b->no_writers, &b->block_lock);
379 +          else
380 +            cond_signal (&b->no_readers_or_writers, &b->block_lock);
381 +        }
382 +      lock_release (&b->block_lock);
383 +
384 +      /* Try again. */
385 +      goto try_again;
386 +    }
387 +
388 +  /* Wait for cache contention to die down. */
389 +  lock_release (&cache_sync);
390 +  timer_msleep (1000);
391 +  goto try_again;
392 +}
393 +
394 +/* Bring block B up-to-date, by reading it from disk if
395 +   necessary, and return a pointer to its data.
396 +   The caller must have an exclusive or non-exclusive lock on
397 +   B. */
398 +void *
399 +cache_read (struct cache_block *b) 
400 +{
401 +  lock_acquire (&b->data_lock);
402 +  if (!b->up_to_date) 
403 +    {
404 +      disk_read (filesys_disk, b->sector, b->data);
405 +      b->up_to_date = true;
406 +      b->dirty = false; 
407 +    }
408 +  lock_release (&b->data_lock);
409 +
410 +  return b->data;
411 +}
412 +
413 +/* Zero out block B, without reading it from disk, and return a
414 +   pointer to the zeroed data.
415 +   The caller must have an exclusive lock on B. */
416 +void *
417 +cache_zero (struct cache_block *b) 
418 +{
419 +  ASSERT (b->writers);
420 +  memset (b->data, 0, DISK_SECTOR_SIZE);
421 +  b->up_to_date = true;
422 +  b->dirty = true;
423 +
424 +  return b->data;
425 +}
426 +
427 +/* Marks block B as dirty, so that it will be written back to
428 +   disk before eviction.
429 +   The caller must have a read or write lock on B,
430 +   and B must be up-to-date. */
431 +void
432 +cache_dirty (struct cache_block *b) 
433 +{
434 +  ASSERT (b->up_to_date);
435 +  b->dirty = true;
436 +}
437 +
438 +/* Unlocks block B.
439 +   If B is no longer locked by any thread, then it becomes a
440 +   candidate for immediate eviction. */
441 +void
442 +cache_unlock (struct cache_block *b) 
443 +{
444 +  lock_acquire (&b->block_lock);
445 +  if (b->readers) 
446 +    {
447 +      ASSERT (b->writers == 0);
448 +      if (--b->readers == 0)
449 +        cond_signal (&b->no_readers_or_writers, &b->block_lock);
450 +    }
451 +  else if (b->writers)
452 +    {
453 +      ASSERT (b->readers == 0);
454 +      ASSERT (b->writers == 1);
455 +      b->writers--;
456 +      if (b->read_waiters)
457 +        cond_broadcast (&b->no_writers, &b->block_lock);
458 +      else
459 +        cond_signal (&b->no_readers_or_writers, &b->block_lock);
460 +    }
461 +  else
462 +    NOT_REACHED ();
463 +  lock_release (&b->block_lock);
464 +}
465 +
466 +/* If SECTOR is in the cache, evicts it immediately without
467 +   writing it back to disk (even if dirty).
468 +   The block must be entirely unused. */
469 +void
470 +cache_free (disk_sector_t sector) 
471 +{
472 +  int i;
473 +  
474 +  lock_acquire (&cache_sync);
475 +  for (i = 0; i < CACHE_CNT; i++)
476 +    {
477 +      struct cache_block *b = &cache[i];
478 +
479 +      lock_acquire (&b->block_lock);
480 +      if (b->sector == sector) 
481 +        {
482 +          lock_release (&cache_sync);
483 +
484 +          /* Only invalidate the block if it's unused.  That
485 +             should be the normal case, but it could be part of a
486 +             read-ahead (in readaheadd()) or write-behind (in
487 +             cache_flush()). */
488 +          if (b->readers == 0 && b->read_waiters == 0
489 +              && b->writers == 0 && b->write_waiters == 0) 
490 +            b->sector = INVALID_SECTOR; 
491 +
492 +          lock_release (&b->block_lock);
493 +          return;
494 +        }
495 +      lock_release (&b->block_lock);
496 +    }
497 +  lock_release (&cache_sync);
498 +}
499 +
500 +void
501 +cache_readahead (disk_sector_t sector) 
502 +{
503 +  readaheadd_submit (sector);
504 +}
505 +\f
506 +/* Flush daemon. */
507 +
508 +static void flushd (void *aux);
509 +
510 +/* Initializes flush daemon. */
511 +static void
512 +flushd_init (void) 
513 +{
514 +  thread_create ("flushd", PRI_MIN, flushd, NULL);
515 +}
516 +
517 +/* Flush daemon thread. */
518 +static void
519 +flushd (void *aux UNUSED) 
520 +{
521 +  for (;;) 
522 +    {
523 +      timer_msleep (30 * 1000);
524 +      cache_flush ();
525 +    }
526 +}
527 +\f
528 +/* A block to read ahead. */
529 +struct readahead_block 
530 +  {
531 +    struct list_elem list_elem;         /* readahead_list element. */
532 +    disk_sector_t sector;               /* Sector to read. */
533 +  };
534 +
535 +/* Protects readahead_list.
536 +   Monitor lock for readahead_list_nonempty. */
537 +static struct lock readahead_lock;
538 +
539 +/* Signaled when a block is added to readahead_list. */
540 +static struct condition readahead_list_nonempty;
541 +
542 +/* List of blocks for read-ahead. */
543 +static struct list readahead_list;
544 +
545 +static void readaheadd (void *aux);
546 +
547 +/* Initialize read-ahead daemon. */
548 +static void
549 +readaheadd_init (void) 
550 +{
551 +  lock_init (&readahead_lock);
552 +  cond_init (&readahead_list_nonempty);
553 +  list_init (&readahead_list);
554 +  thread_create ("readaheadd", PRI_MIN, readaheadd, NULL);
555 +}
556 +
557 +/* Adds SECTOR to the read-ahead queue. */
558 +static void
559 +readaheadd_submit (disk_sector_t sector) 
560 +{
561 +  /* Allocate readahead block. */
562 +  struct readahead_block *block = malloc (sizeof *block);
563 +  if (block == NULL)
564 +    return;
565 +  block->sector = sector;
566 +
567 +  /* Add block to list. */
568 +  lock_acquire (&readahead_lock);
569 +  list_push_back (&readahead_list, &block->list_elem);
570 +  cond_signal (&readahead_list_nonempty, &readahead_lock);
571 +  lock_release (&readahead_lock);
572 +}
573 +
574 +/* Read-ahead daemon. */
575 +static void
576 +readaheadd (void *aux UNUSED) 
577 +{
578 +  for (;;) 
579 +    {
580 +      struct readahead_block *ra_block;
581 +      struct cache_block *cache_block;
582 +
583 +      /* Get readahead block from list. */
584 +      lock_acquire (&readahead_lock);
585 +      while (list_empty (&readahead_list)) 
586 +        cond_wait (&readahead_list_nonempty, &readahead_lock);
587 +      ra_block = list_entry (list_pop_front (&readahead_list),
588 +                             struct readahead_block, list_elem);
589 +      lock_release (&readahead_lock);
590 +
591 +      /* Read block into cache. */
592 +      cache_block = cache_lock (ra_block->sector, NON_EXCLUSIVE);
593 +      cache_read (cache_block);
594 +      cache_unlock (cache_block);
595 +      free (ra_block);
596 +    }
597 +}
598 Index: src/filesys/cache.h
599 diff -u src/filesys/cache.h~ src/filesys/cache.h
600 --- src/filesys/cache.h~
601 +++ src/filesys/cache.h
602 @@ -0,0 +1,23 @@
603 +#ifndef FILESYS_CACHE_H
604 +#define FILESYS_CACHE_H
605 +
606 +#include "devices/disk.h"
607 +
608 +/* Type of block lock. */
609 +enum lock_type 
610 +  {
611 +    NON_EXCLUSIVE,     /* Any number of lockers. */
612 +    EXCLUSIVE          /* Only one locker. */
613 +  };
614 +
615 +void cache_init (void);
616 +void cache_flush (void);
617 +struct cache_block *cache_lock (disk_sector_t, enum lock_type);
618 +void *cache_read (struct cache_block *);
619 +void *cache_zero (struct cache_block *);
620 +void cache_dirty (struct cache_block *);
621 +void cache_unlock (struct cache_block *);
622 +void cache_free (disk_sector_t);
623 +void cache_readahead (disk_sector_t);
624 +
625 +#endif /* filesys/cache.h */
626 Index: src/filesys/directory.c
627 diff -u src/filesys/directory.c~ src/filesys/directory.c
628 --- src/filesys/directory.c~
629 +++ src/filesys/directory.c
630 @@ -21,12 +21,36 @@ struct dir_entry 
631      bool in_use;                        /* In use or free? */
632    };
633  
634 -/* Creates a directory with space for ENTRY_CNT entries in the
635 -   given SECTOR.  Returns true if successful, false on failure. */
636 +/* Creates a directory in the given SECTOR.
637 +   The directory's parent is in PARENT_SECTOR. */
638  bool
639 -dir_create (disk_sector_t sector, size_t entry_cnt) 
640 +dir_create (disk_sector_t sector, disk_sector_t parent_sector) 
641  {
642 -  return inode_create (sector, entry_cnt * sizeof (struct dir_entry));
643 +  struct inode *inode = inode_create (sector, DIR_INODE);
644 +  bool success = inode != NULL;
645 +  if (success) 
646 +    {
647 +      struct dir_entry entries[2];
648 +
649 +      memset (entries, 0, sizeof entries);
650 +
651 +      /* "." entry. */
652 +      entries[0].inode_sector = sector;
653 +      strlcpy (entries[0].name, ".", sizeof entries[0].name);
654 +      entries[0].in_use = true;
655 +
656 +      /* ".." entry. */
657 +      entries[1].inode_sector = parent_sector;
658 +      strlcpy (entries[1].name, "..", sizeof entries[1].name);
659 +      entries[1].in_use = true;
660 +      
661 +      success = (inode_write_at (inode, entries, sizeof entries, 0)
662 +                 == sizeof entries);
663 +      if (!success)
664 +        inode_remove (inode);
665 +    }
666 +  inode_close (inode); 
667 +  return success;
668  }
669  
670  /* Opens and returns the directory for the given INODE, of which
671 @@ -35,7 +59,7 @@ struct dir *
672  dir_open (struct inode *inode) 
673  {
674    struct dir *dir = calloc (1, sizeof *dir);
675 -  if (inode != NULL && dir != NULL)
676 +  if (inode != NULL && dir != NULL && inode_get_type (inode) == DIR_INODE)
677      {
678        dir->inode = inode;
679        dir->pos = 0;
680 @@ -84,10 +108,8 @@ dir_get_inode (struct dir *dir) 
681  }
682  
683  /* Searches DIR for a file with the given NAME.
684 -   If successful, returns true, sets *EP to the directory entry
685 -   if EP is non-null, and sets *OFSP to the byte offset of the
686 -   directory entry if OFSP is non-null.
687 -   otherwise, returns false and ignores EP and OFSP. */
688 +   If successful, returns the file's entry;
689 +   otherwise, returns a null pointer. */
690  static bool
691  lookup (const struct dir *dir, const char *name,
692          struct dir_entry *ep, off_t *ofsp) 
693 @@ -120,15 +142,16 @@ dir_lookup (const struct dir *dir, const
694              struct inode **inode) 
695  {
696    struct dir_entry e;
697 +  bool ok;
698  
699    ASSERT (dir != NULL);
700    ASSERT (name != NULL);
701  
702 -  if (lookup (dir, name, &e, NULL))
703 -    *inode = inode_open (e.inode_sector);
704 -  else
705 -    *inode = NULL;
706 +  inode_lock (dir->inode);
707 +  ok = lookup (dir, name, &e, NULL);
708 +  inode_unlock (dir->inode);
709  
710 +  *inode = ok ? inode_open (e.inode_sector) : NULL;
711    return *inode != NULL;
712  }
713  
714 @@ -149,10 +172,11 @@ dir_add (struct dir *dir, const char *na
715    ASSERT (name != NULL);
716  
717    /* Check NAME for validity. */
718 -  if (*name == '\0' || strlen (name) > NAME_MAX)
719 +  if (*name == '\0' || strchr (name, '/') || strlen (name) > NAME_MAX)
720      return false;
721  
722    /* Check that NAME is not in use. */
723 +  inode_lock (dir->inode);
724    if (lookup (dir, name, NULL, NULL))
725      goto done;
726  
727 @@ -175,6 +199,7 @@ dir_add (struct dir *dir, const char *na
728    success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
729  
730   done:
731 +  inode_unlock (dir->inode);
732    return success;
733  }
734  
735 @@ -192,13 +217,37 @@ dir_remove (struct dir *dir, const char 
736    ASSERT (dir != NULL);
737    ASSERT (name != NULL);
738  
739 +  if (!strcmp (name, ".") || !strcmp (name, ".."))
740 +    return false;
741 +
742    /* Find directory entry. */
743 +  inode_lock (dir->inode);
744    if (!lookup (dir, name, &e, &ofs))
745      goto done;
746  
747    /* Open inode. */
748    inode = inode_open (e.inode_sector);
749    if (inode == NULL)
750      goto done;
751  
752 +  /* Verify that it is not an in-use or non-empty directory. */
753 +  if (inode_get_type (inode) == DIR_INODE)
754 +    {
755 +      struct dir_entry e2;
756 +      off_t pos;
757 +
758 +      if (inode_open_cnt (inode) != 1)
759 +        goto done;
760 +
761 +      inode_lock (inode);
762 +      for (pos = 0; inode_read_at (inode, &e2, sizeof e2, pos) == sizeof e2;
763 +           pos += sizeof e2)
764 +        if (e2.in_use && strcmp (e2.name, ".") && strcmp (e2.name, ".."))
765 +          {
766 +            inode_unlock (inode);
767 +            goto done;
768 +          }
769 +      inode_unlock (inode);
770 +    }
771
772    /* Erase directory entry. */
773 @@ -211,6 +241,7 @@ dir_remove (struct dir *dir, const char 
774    success = true;
775  
776   done:
777 +  inode_unlock (dir->inode);
778    inode_close (inode);
779    return success;
780  }
781 @@ -223,14 +254,17 @@ dir_readdir (struct dir *dir, char name[
782  {
783    struct dir_entry e;
784  
785 +  inode_lock (dir->inode);
786    while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) 
787      {
788        dir->pos += sizeof e;
789 -      if (e.in_use)
790 +      if (e.in_use && strcmp (e.name, ".") && strcmp (e.name, ".."))
791          {
792 +          inode_unlock (dir->inode);
793            strlcpy (name, e.name, NAME_MAX + 1);
794            return true;
795          } 
796      }
797 +  inode_unlock (dir->inode);
798    return false;
799  }
800 Index: src/filesys/directory.h
801 diff -u src/filesys/directory.h~ src/filesys/directory.h
802 --- src/filesys/directory.h~
803 +++ src/filesys/directory.h
804 @@ -14,7 +14,7 @@
805  struct inode;
806  
807  /* Opening and closing directories. */
808 -bool dir_create (disk_sector_t sector, size_t entry_cnt);
809 +bool dir_create (disk_sector_t sector, disk_sector_t parent_sector);
810  struct dir *dir_open (struct inode *);
811  struct dir *dir_open_root (void);
812  struct dir *dir_reopen (struct dir *);
813 Index: src/filesys/file.c
814 diff -u src/filesys/file.c~ src/filesys/file.c
815 --- src/filesys/file.c~
816 +++ src/filesys/file.c
817 @@ -11,6 +11,24 @@ struct file 
818      bool deny_write;            /* Has file_deny_write() been called? */
819    };
820  
821 +/* Creates a file in the given SECTOR,
822 +   initially LENGTH bytes long. */
823 +bool
824 +file_create (disk_sector_t sector, off_t length) 
825 +{
826 +  struct inode *inode = inode_create (sector, FILE_INODE);
827 +  bool success = inode != NULL;
828 +  if (success && length != 0) 
829 +    {
830 +      ASSERT (length >= 0);
831 +      success = inode_write_at (inode, "", 1, length - 1) == 1;
832 +      if (!success)
833 +        inode_remove (inode); 
834 +    }
835 +  inode_close (inode);
836 +  return success;
837 +}
838 +
839  /* Opens a file for the given INODE, of which it takes ownership,
840     and returns the new file.  Returns a null pointer if an
841     allocation fails or if INODE is null. */
842 @@ -18,7 +34,7 @@ struct file *
843  file_open (struct inode *inode) 
844  {
845    struct file *file = calloc (1, sizeof *file);
846 -  if (inode != NULL && file != NULL)
847 +  if (inode != NULL && file != NULL && inode_get_type (inode) == FILE_INODE)
848      {
849        file->inode = inode;
850        file->pos = 0;
851 Index: src/filesys/file.h
852 diff -u src/filesys/file.h~ src/filesys/file.h
853 --- src/filesys/file.h~
854 +++ src/filesys/file.h
855 @@ -1,11 +1,14 @@
856  #ifndef FILESYS_FILE_H
857  #define FILESYS_FILE_H
858  
859 +#include <stdbool.h>
860 +#include "devices/disk.h"
861  #include "filesys/off_t.h"
862  
863  struct inode;
864  
865  /* Opening and closing files. */
866 +bool file_create (disk_sector_t sector, off_t length);
867  struct file *file_open (struct inode *);
868  struct file *file_reopen (struct file *);
869  void file_close (struct file *);
870 Index: src/filesys/filesys.c
871 diff -u src/filesys/filesys.c~ src/filesys/filesys.c
872 --- src/filesys/filesys.c~
873 +++ src/filesys/filesys.c
874 @@ -2,11 +2,13 @@
875  #include <debug.h>
876  #include <stdio.h>
877  #include <string.h>
878 +#include "filesys/cache.h"
879  #include "filesys/file.h"
880  #include "filesys/free-map.h"
881  #include "filesys/inode.h"
882  #include "filesys/directory.h"
883  #include "devices/disk.h"
884 +#include "threads/thread.h"
885  
886  /* The disk that contains the file system. */
887  struct disk *filesys_disk;
888 @@ -23,6 +25,7 @@ filesys_init (bool format) 
889      PANIC ("hd0:1 (hdb) not present, file system initialization failed");
890  
891    inode_init ();
892 +  cache_init ();
893    free_map_init ();
894  
895    if (format) 
896 @@ -37,6 +40,130 @@ void
897  filesys_done (void) 
898  {
899    free_map_close ();
900 +  cache_flush ();
901 +}
902 +\f
903 +/* Extracts a file name part from *SRCP into PART,
904 +   and updates *SRCP so that the next call will return the next
905 +   file name part.
906 +   Returns 1 if successful, 0 at end of string, -1 for a too-long
907 +   file name part. */
908 +static int
909 +get_next_part (char part[NAME_MAX], const char **srcp)
910 +{
911 +  const char *src = *srcp;
912 +  char *dst = part;
913 +
914 +  /* Skip leading slashes.
915 +     If it's all slashes, we're done. */
916 +  while (*src == '/')
917 +    src++;
918 +  if (*src == '\0')
919 +    return 0;
920 +
921 +  /* Copy up to NAME_MAX character from SRC to DST.
922 +     Add null terminator. */
923 +  while (*src != '/' && *src != '\0') 
924 +    {
925 +      if (dst < part + NAME_MAX)
926 +        *dst++ = *src;
927 +      else
928 +        return -1;
929 +      src++; 
930 +    }
931 +  *dst = '\0';
932 +
933 +  /* Advance source pointer. */
934 +  *srcp = src;
935 +  return 1;
936 +}
937 +
938 +/* Resolves relative or absolute file NAME.
939 +   Returns true if successful, false on failure.
940 +   Stores the directory corresponding to the name into *DIRP,
941 +   and the file name part into BASE_NAME. */
942 +static bool
943 +resolve_name_to_entry (const char *name,
944 +                       struct dir **dirp, char base_name[NAME_MAX + 1]) 
945 +{
946 +  struct dir *dir = NULL;
947 +  struct inode *inode;
948 +  const char *cp;
949 +  char part[NAME_MAX + 1], next_part[NAME_MAX + 1];
950 +  int ok;
951 +
952 +  /* Find starting directory. */
953 +  if (name[0] == '/' || thread_current ()->wd == NULL)
954 +    dir = dir_open_root ();
955 +  else
956 +    dir = dir_reopen (thread_current ()->wd);
957 +  if (dir == NULL)
958 +    goto error;
959 +
960 +  /* Get first name part. */
961 +  cp = name;
962 +  if (get_next_part (part, &cp) <= 0)
963 +    goto error;
964 +
965 +  /* As long as another part follows the current one,
966 +     traverse down another directory. */
967 +  while ((ok = get_next_part (next_part, &cp)) > 0)
968 +    {
969 +      if (!dir_lookup (dir, part, &inode))
970 +        goto error;
971 +
972 +      dir_close (dir);
973 +      dir = dir_open (inode);
974 +      if (dir == NULL)
975 +        goto error;
976 +
977 +      strlcpy (part, next_part, NAME_MAX + 1);
978 +    }
979 +  if (ok < 0)
980 +    goto error;
981 +
982 +  /* Return our results. */
983 +  *dirp = dir;
984 +  strlcpy (base_name, part, NAME_MAX + 1);
985 +  return true;
986 +
987 + error:
988 +  /* Return failure. */
989 +  dir_close (dir);
990 +  *dirp = NULL;
991 +  base_name[0] = '\0';
992 +  return false;
993 +}
994 +
995 +/* Resolves relative or absolute file NAME to an inode.
996 +   Returns an inode if successful, or a null pointer on failure.
997 +   The caller is responsible for closing the returned inode. */
998 +static struct inode *
999 +resolve_name_to_inode (const char *name)
1000 +{
1001 +  if (name[0] == '/' && name[strspn (name, "/")] == '\0') 
1002 +    {
1003 +      /* The name represents the root directory.
1004 +         There's no name part at all, so resolve_name_to_entry()
1005 +         would reject it entirely.
1006 +         Special case it. */
1007 +      return inode_open (ROOT_DIR_SECTOR);
1008 +    }
1009 +  else 
1010 +    {
1011 +      struct dir *dir;
1012 +      char base_name[NAME_MAX + 1];
1013 +
1014 +      if (resolve_name_to_entry (name, &dir, base_name)) 
1015 +        {
1016 +          struct inode *inode;
1017 +          dir_lookup (dir, base_name, &inode);
1018 +          dir_close (dir);
1019 +          return inode; 
1020 +        }
1021 +      else
1022 +        return NULL;
1023 +    }
1024  }
1025  \f
1026  /* Creates a file named NAME with the given INITIAL_SIZE.
1027 @@ -44,16 +171,24 @@ filesys_done (void) 
1028     Fails if a file named NAME already exists,
1029     or if internal memory allocation fails. */
1030  bool
1031 -filesys_create (const char *name, off_t initial_size) 
1032 +filesys_create (const char *name, off_t initial_size, enum inode_type type) 
1033  {
1034 +  struct dir *dir;
1035 +  char base_name[NAME_MAX + 1];
1036    disk_sector_t inode_sector = 0;
1037 -  struct dir *dir = dir_open_root ();
1038 -  bool success = (dir != NULL
1039 -                  && free_map_allocate (1, &inode_sector)
1040 -                  && inode_create (inode_sector, initial_size)
1041 -                  && dir_add (dir, name, inode_sector));
1042 +  bool success = (resolve_name_to_entry (name, &dir, base_name)
1043 +                  && free_map_allocate (&inode_sector));
1044 +  if (success) 
1045 +    {
1046 +      if (type == FILE_INODE)
1047 +        success = file_create (inode_sector, initial_size);
1048 +      else
1049 +        success = dir_create (inode_sector,
1050 +                              inode_get_inumber (dir_get_inode (dir))); 
1051 +    }
1052 +  success = success && dir_add (dir, base_name, inode_sector);
1053    if (!success && inode_sector != 0) 
1054 -    free_map_release (inode_sector, 1);
1055 +    free_map_release (inode_sector);
1056    dir_close (dir);
1057  
1058    return success;
1059 @@ -64,17 +199,10 @@ filesys_create (const char *name, off_t 
1060     otherwise.
1061     Fails if no file named NAME exists,
1062     or if an internal memory allocation fails. */
1063 -struct file *
1064 +struct inode *
1065  filesys_open (const char *name)
1066  {
1067 -  struct dir *dir = dir_open_root ();
1068 -  struct inode *inode = NULL;
1069 -
1070 -  if (dir != NULL)
1071 -    dir_lookup (dir, name, &inode);
1072 -  dir_close (dir);
1073 -
1074 -  return file_open (inode);
1075 +  return resolve_name_to_inode (name);
1076  }
1077  
1078  /* Deletes the file named NAME.
1079 @@ -84,12 +212,35 @@ filesys_open (const char *name)
1080  bool
1081  filesys_remove (const char *name) 
1082  {
1083 -  struct dir *dir = dir_open_root ();
1084 -  bool success = dir != NULL && dir_remove (dir, name);
1085 -  dir_close (dir); 
1086 +  struct dir *dir;
1087 +  char base_name[NAME_MAX + 1];
1088 +  bool success;
1089  
1090 +  if (resolve_name_to_entry (name, &dir, base_name)) 
1091 +    {
1092 +      success = dir_remove (dir, base_name);
1093 +      dir_close (dir);
1094 +    }
1095 +  else
1096 +    success = false;
1097 +  
1098    return success;
1099  }
1100 +/* Change current directory to NAME.
1101 +   Return true if successful, false on failure. */
1102 +bool
1103 +filesys_chdir (const char *name) 
1104 +{
1105 +  struct dir *dir = dir_open (resolve_name_to_inode (name));
1106 +  if (dir != NULL) 
1107 +    {
1108 +      dir_close (thread_current ()->wd);
1109 +      thread_current ()->wd = dir;
1110 +      return true;
1111 +    }
1112 +  else
1113 +    return false;
1114 +}
1115  \f
1116  static void must_succeed_function (int, bool) NO_INLINE;
1117  #define MUST_SUCCEED(EXPR) must_succeed_function (__LINE__, EXPR)
1118 @@ -155,9 +306,15 @@ static void
1119  do_format (void)
1120  {
1121    printf ("Formatting file system...");
1122 +
1123 +  /* Set up free map. */
1124    free_map_create ();
1125 -  if (!dir_create (ROOT_DIR_SECTOR, 16))
1126 +
1127 +  /* Set up root directory. */
1128 +  if (!dir_create (ROOT_DIR_SECTOR, ROOT_DIR_SECTOR))
1129      PANIC ("root directory creation failed");
1130 +
1131    free_map_close ();
1132 +
1133    printf ("done.\n");
1134  }
1135 Index: src/filesys/filesys.h
1136 diff -u src/filesys/filesys.h~ src/filesys/filesys.h
1137 --- src/filesys/filesys.h~
1138 +++ src/filesys/filesys.h
1139 @@ -3,6 +3,7 @@
1140  
1141  #include <stdbool.h>
1142  #include "filesys/off_t.h"
1143 +#include "filesys/inode.h"
1144  
1145  /* Sectors of system file inodes. */
1146  #define FREE_MAP_SECTOR 0       /* Free map file inode sector. */
1147 @@ -13,9 +14,10 @@ extern struct disk *filesys_disk;
1148  
1149  void filesys_init (bool format);
1150  void filesys_done (void);
1151 -bool filesys_create (const char *name, off_t initial_size);
1152 -struct file *filesys_open (const char *name);
1153 +bool filesys_create (const char *name, off_t initial_size, enum inode_type);
1154 +struct inode *filesys_open (const char *name);
1155  bool filesys_remove (const char *name);
1156 +bool filesys_chdir (const char *name);
1157  
1158  void filesys_self_test (void);
1159  
1160 Index: src/filesys/free-map.c
1161 diff -u src/filesys/free-map.c~ src/filesys/free-map.c
1162 --- src/filesys/free-map.c~
1163 +++ src/filesys/free-map.c
1164 @@ -3,15 +3,18 @@
1165  #include <debug.h>
1166  #include "filesys/file.h"
1167  #include "filesys/filesys.h"
1168 -#include "filesys/inode.h"
1169 +#include "threads/synch.h"
1170  
1171  static struct file *free_map_file;   /* Free map file. */
1172  static struct bitmap *free_map;      /* Free map, one bit per disk sector. */
1173 +static struct lock free_map_lock;    /* Mutual exclusion. */
1174  
1175  /* Initializes the free map. */
1176  void
1177  free_map_init (void) 
1178  {
1179 +  lock_init (&free_map_lock);
1180 +
1181    free_map = bitmap_create (disk_size (filesys_disk));
1182    if (free_map == NULL)
1183      PANIC ("bitmap creation failed--disk is too large");
1184 @@ -19,33 +22,32 @@ free_map_init (void) 
1185    bitmap_mark (free_map, ROOT_DIR_SECTOR);
1186  }
1187  
1188 -/* Allocates CNT consecutive sectors from the free map and stores
1189 -   the first into *SECTORP.
1190 -   Returns true if successful, false if all sectors were
1191 +/* Allocates a sector from the free map and stores it into
1192 +   *SECTORP.
1193 +   Return true if successful, false if all sectors were
1194     available. */
1195  bool
1196 -free_map_allocate (size_t cnt, disk_sector_t *sectorp) 
1197 +free_map_allocate (disk_sector_t *sectorp) 
1198  {
1199 -  disk_sector_t sector = bitmap_scan_and_flip (free_map, 0, cnt, false);
1200 -  if (sector != BITMAP_ERROR
1201 -      && free_map_file != NULL
1202 -      && !bitmap_write (free_map, free_map_file))
1203 -    {
1204 -      bitmap_set_multiple (free_map, sector, cnt, false); 
1205 -      sector = BITMAP_ERROR;
1206 -    }
1207 -  if (sector != BITMAP_ERROR)
1208 +  size_t sector;
1209 +  
1210 +  lock_acquire (&free_map_lock);
1211 +  sector = bitmap_scan_and_flip (free_map, 0, 1, false);
1212 +  lock_release (&free_map_lock);
1213 +
1214 +  if (sector != BITMAP_ERROR) 
1215      *sectorp = sector;
1216    return sector != BITMAP_ERROR;
1217  }
1218  
1219 -/* Makes CNT sectors starting at SECTOR available for use. */
1220 +/* Makes SECTOR available for use. */
1221  void
1222 -free_map_release (disk_sector_t sector, size_t cnt)
1223 +free_map_release (disk_sector_t sector)
1224  {
1225 -  ASSERT (bitmap_all (free_map, sector, cnt));
1226 -  bitmap_set_multiple (free_map, sector, cnt, false);
1227 -  bitmap_write (free_map, free_map_file);
1228 +  lock_acquire (&free_map_lock);
1229 +  ASSERT (bitmap_test (free_map, sector));
1230 +  bitmap_reset (free_map, sector);
1231 +  lock_release (&free_map_lock);
1232  }
1233  
1234  /* Opens the free map file and reads it from disk. */
1235 @@ -63,6 +65,8 @@ free_map_open (void) 
1236  void
1237  free_map_close (void) 
1238  {
1239 +  if (!bitmap_write (free_map, free_map_file))
1240 +    PANIC ("can't write free map");
1241    file_close (free_map_file);
1242  }
1243  
1244 @@ -72,7 +76,7 @@ void
1245  free_map_create (void) 
1246  {
1247    /* Create inode. */
1248 -  if (!inode_create (FREE_MAP_SECTOR, bitmap_file_size (free_map)))
1249 +  if (!file_create (FREE_MAP_SECTOR, 0))
1250      PANIC ("free map creation failed");
1251  
1252    /* Write bitmap to file. */
1253 Index: src/filesys/free-map.h
1254 diff -u src/filesys/free-map.h~ src/filesys/free-map.h
1255 --- src/filesys/free-map.h~
1256 +++ src/filesys/free-map.h
1257 @@ -11,7 +11,7 @@ void free_map_create (void);
1258  void free_map_open (void);
1259  void free_map_close (void);
1260  
1261 -bool free_map_allocate (size_t, disk_sector_t *);
1262 -void free_map_release (disk_sector_t, size_t);
1263 +bool free_map_allocate (disk_sector_t *);
1264 +void free_map_release (disk_sector_t);
1265  
1266  #endif /* filesys/free-map.h */
1267 Index: src/filesys/fsutil.c
1268 diff -u src/filesys/fsutil.c~ src/filesys/fsutil.c
1269 --- src/filesys/fsutil.c~
1270 +++ src/filesys/fsutil.c
1271 @@ -38,7 +38,7 @@ fsutil_cat (char **argv)
1272    char *buffer;
1273  
1274    printf ("Printing '%s' to the console...\n", file_name);
1275 -  file = filesys_open (file_name);
1276 +  file = file_open (filesys_open (file_name));
1277    if (file == NULL)
1278      PANIC ("%s: open failed", file_name);
1279    buffer = palloc_get_page (PAL_ASSERT);
1280 @@ -110,9 +110,9 @@ fsutil_put (char **argv) 
1281      PANIC ("%s: invalid file size %d", file_name, size);
1282    
1283    /* Create destination file. */
1284 -  if (!filesys_create (file_name, size))
1285 +  if (!filesys_create (file_name, size, FILE_INODE))
1286      PANIC ("%s: create failed", file_name);
1287 -  dst = filesys_open (file_name);
1288 +  dst = file_open (filesys_open (file_name));
1289    if (dst == NULL)
1290      PANIC ("%s: open failed", file_name);
1291  
1292 @@ -162,7 +162,7 @@ fsutil_get (char **argv)
1293      PANIC ("couldn't allocate buffer");
1294  
1295    /* Open source file. */
1296 -  src = filesys_open (file_name);
1297 +  src = file_open (filesys_open (file_name));
1298    if (src == NULL)
1299      PANIC ("%s: open failed", file_name);
1300    size = file_length (src);
1301 Index: src/filesys/inode.c
1302 diff -u src/filesys/inode.c~ src/filesys/inode.c
1303 --- src/filesys/inode.c~
1304 +++ src/filesys/inode.c
1305 @@ -1,23 +1,38 @@
1306  #include "filesys/inode.h"
1307 +#include <bitmap.h>
1308  #include <list.h>
1309  #include <debug.h>
1310  #include <round.h>
1311 +#include <stdio.h>
1312  #include <string.h>
1313 +#include "filesys/cache.h"
1314  #include "filesys/filesys.h"
1315  #include "filesys/free-map.h"
1316  #include "threads/malloc.h"
1317 +#include "threads/synch.h"
1318  
1319  /* Identifies an inode. */
1320  #define INODE_MAGIC 0x494e4f44
1321  
1322 +#define DIRECT_CNT 123
1323 +#define INDIRECT_CNT 1
1324 +#define DBL_INDIRECT_CNT 1
1325 +#define SECTOR_CNT (DIRECT_CNT + INDIRECT_CNT + DBL_INDIRECT_CNT)
1326 +
1327 +#define PTRS_PER_SECTOR ((off_t) (DISK_SECTOR_SIZE / sizeof (disk_sector_t))) 
1328 +#define INODE_SPAN ((DIRECT_CNT                                              \
1329 +                     + PTRS_PER_SECTOR * INDIRECT_CNT                        \
1330 +                     + PTRS_PER_SECTOR * PTRS_PER_SECTOR * DBL_INDIRECT_CNT) \
1331 +                    * DISK_SECTOR_SIZE)
1332 +
1333  /* On-disk inode.
1334     Must be exactly DISK_SECTOR_SIZE bytes long. */
1335  struct inode_disk
1336    {
1337 -    disk_sector_t start;                /* First data sector. */
1338 +    disk_sector_t sectors[SECTOR_CNT];  /* Sectors. */
1339 +    enum inode_type type;               /* FILE_INODE or DIR_INODE. */
1340      off_t length;                       /* File size in bytes. */
1341      unsigned magic;                     /* Magic number. */
1342 -    uint32_t unused[125];               /* Not used. */
1343    };
1344  
1345  /* Returns the number of sectors to allocate for an inode SIZE
1346 @@ -35,74 +50,54 @@ struct inode 
1347      disk_sector_t sector;               /* Sector number of disk location. */
1348      int open_cnt;                       /* Number of openers. */
1349      bool removed;                       /* True if deleted, false otherwise. */
1350 +    struct lock lock;                   /* Protects the inode. */
1351 +
1352 +    /* Denying writes. */
1353 +    struct lock deny_write_lock;        /* Protects members below. */
1354 +    struct condition no_writers_cond;   /* Signaled when no writers. */ 
1355      int deny_write_cnt;                 /* 0: writes ok, >0: deny writes. */
1356 -    struct inode_disk data;             /* Inode content. */
1357 +    int writer_cnt;                     /* Number of writers. */
1358    };
1359  
1360 -/* Returns the disk sector that contains byte offset POS within
1361 -   INODE.
1362 -   Returns -1 if INODE does not contain data for a byte at offset
1363 -   POS. */
1364 -static disk_sector_t
1365 -byte_to_sector (const struct inode *inode, off_t pos) 
1366 -{
1367 -  ASSERT (inode != NULL);
1368 -  if (pos < inode->data.length)
1369 -    return inode->data.start + pos / DISK_SECTOR_SIZE;
1370 -  else
1371 -    return -1;
1372 -}
1373 -
1374  /* List of open inodes, so that opening a single inode twice
1375     returns the same `struct inode'. */
1376  static struct list open_inodes;
1377  
1378 +/* Controls access to open_inodes list. */
1379 +static struct lock open_inodes_lock;
1380 +
1381 +static void deallocate_inode (const struct inode *);
1382 +
1383  /* Initializes the inode module. */
1384  void
1385  inode_init (void) 
1386  {
1387    list_init (&open_inodes);
1388 +  lock_init (&open_inodes_lock);
1389  }
1390  
1391 -/* Initializes an inode with LENGTH bytes of data and
1392 -   writes the new inode to sector SECTOR on the file system
1393 -   disk.
1394 -   Returns true if successful.
1395 -   Returns false if memory or disk allocation fails. */
1396 -bool
1397 -inode_create (disk_sector_t sector, off_t length)
1398 +/* Initializes an inode of the given TYPE, writes the new inode
1399 +   to sector SECTOR on the file system disk, and returns the
1400 +   inode thus created.  Returns a null pointer if unsuccessful. */   
1401 +struct inode *
1402 +inode_create (disk_sector_t sector, enum inode_type type) 
1403  {
1404 -  struct inode_disk *disk_inode = NULL;
1405 -  bool success = false;
1406 +  struct cache_block *block;
1407 +  struct inode_disk *disk_inode;
1408  
1409 -  ASSERT (length >= 0);
1410 +  block = cache_lock (sector, EXCLUSIVE);
1411  
1412    /* If this assertion fails, the inode structure is not exactly
1413       one sector in size, and you should fix that. */
1414    ASSERT (sizeof *disk_inode == DISK_SECTOR_SIZE);
1415 +  disk_inode = cache_zero (block);
1416 +  disk_inode->type = type;
1417 +  disk_inode->length = 0;
1418 +  disk_inode->magic = INODE_MAGIC;
1419 +  cache_dirty (block);
1420 +  cache_unlock (block);
1421  
1422 -  disk_inode = calloc (1, sizeof *disk_inode);
1423 -  if (disk_inode != NULL)
1424 -    {
1425 -      size_t sectors = bytes_to_sectors (length);
1426 -      disk_inode->length = length;
1427 -      disk_inode->magic = INODE_MAGIC;
1428 -      if (free_map_allocate (sectors, &disk_inode->start))
1429 -        {
1430 -          disk_write (filesys_disk, sector, disk_inode);
1431 -          if (sectors > 0) 
1432 -            {
1433 -              static char zeros[DISK_SECTOR_SIZE];
1434 -              size_t i;
1435 -              
1436 -              for (i = 0; i < sectors; i++) 
1437 -                disk_write (filesys_disk, disk_inode->start + i, zeros); 
1438 -            }
1439 -          success = true; 
1440 -        } 
1441 -      free (disk_inode);
1442 -    }
1443 -  return success;
1444 +  return inode_open (sector);
1445  }
1446  
1447  /* Reads an inode from SECTOR
1448 @@ -115,29 +110,35 @@ inode_open (disk_sector_t sector) 
1449    struct inode *inode;
1450  
1451    /* Check whether this inode is already open. */
1452 +  lock_acquire (&open_inodes_lock);
1453    for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
1454         e = list_next (e)) 
1455      {
1456        inode = list_entry (e, struct inode, elem);
1457        if (inode->sector == sector) 
1458          {
1459 -          inode_reopen (inode);
1460 -          return inode; 
1461 +          inode->open_cnt++;
1462 +          goto done; 
1463          }
1464      }
1465  
1466    /* Allocate memory. */
1467    inode = malloc (sizeof *inode);
1468    if (inode == NULL)
1469 -    return NULL;
1470 +    goto done;
1471  
1472    /* Initialize. */
1473    list_push_front (&open_inodes, &inode->elem);
1474    inode->sector = sector;
1475    inode->open_cnt = 1;
1476 +  lock_init (&inode->lock);
1477    inode->deny_write_cnt = 0;
1478 +  lock_init (&inode->deny_write_lock);
1479 +  cond_init (&inode->no_writers_cond);
1480    inode->removed = false;
1481 -  disk_read (filesys_disk, inode->sector, &inode->data);
1482 +  
1483 + done:
1484 +  lock_release (&open_inodes_lock);
1485    return inode;
1486  }
1487  
1488 @@ -146,9 +147,24 @@ struct inode *
1489  inode_reopen (struct inode *inode)
1490  {
1491    if (inode != NULL)
1492 -    inode->open_cnt++;
1493 +    {
1494 +      lock_acquire (&open_inodes_lock);
1495 +      inode->open_cnt++;
1496 +      lock_release (&open_inodes_lock);
1497 +    }
1498    return inode;
1499  }
1500  
1501 +/* Returns the type of INODE. */
1502 +enum inode_type
1503 +inode_get_type (const struct inode *inode) 
1504 +{
1505 +  struct cache_block *inode_block = cache_lock (inode->sector, NON_EXCLUSIVE);
1506 +  struct inode_disk *disk_inode = cache_read (inode_block);
1507 +  enum inode_type type = disk_inode->type;
1508 +  cache_unlock (inode_block);
1509 +  return type;
1510 +}
1511 +
1512  /* Returns INODE's inode number. */
1513  disk_sector_t
1514 @@ -161,21 +183,60 @@ inode_close (struct inode *inode) 
1515      return;
1516  
1517    /* Release resources if this was the last opener. */
1518 +  lock_acquire (&open_inodes_lock);
1519    if (--inode->open_cnt == 0)
1520      {
1521        /* Remove from inode list and release lock. */
1522        list_remove (&inode->elem);
1523 +      lock_release (&open_inodes_lock);
1524   
1525        /* Deallocate blocks if removed. */
1526        if (inode->removed) 
1527 -        {
1528 -          free_map_release (inode->sector, 1);
1529 -          free_map_release (inode->data.start,
1530 -                            bytes_to_sectors (inode->data.length)); 
1531 -        }
1532 +        deallocate_inode (inode);
1533  
1534        free (inode); 
1535      }
1536 +  else
1537 +    lock_release (&open_inodes_lock);
1538 +}
1539 +
1540 +/* Deallocates SECTOR and anything it points to recursively.
1541 +   LEVEL is 2 if SECTOR is doubly indirect,
1542 +   or 1 if SECTOR is indirect,
1543 +   or 0 if SECTOR is a data sector. */
1544 +static void
1545 +deallocate_recursive (disk_sector_t sector, int level) 
1546 +{
1547 +  if (level > 0) 
1548 +    {
1549 +      struct cache_block *block = cache_lock (sector, EXCLUSIVE);
1550 +      disk_sector_t *pointers = cache_read (block);
1551 +      int i;
1552 +      for (i = 0; i < PTRS_PER_SECTOR; i++)
1553 +        if (pointers[i])
1554 +          deallocate_recursive (sector, level - 1);
1555 +      cache_unlock (block);
1556 +    }
1557 +  
1558 +  cache_free (sector);
1559 +  free_map_release (sector);
1560 +}
1561 +
1562 +/* Deallocates the blocks allocated for INODE. */
1563 +static void
1564 +deallocate_inode (const struct inode *inode)
1565 +{
1566 +  struct cache_block *block = cache_lock (inode->sector, EXCLUSIVE);
1567 +  struct inode_disk *disk_inode = cache_read (block);
1568 +  int i;
1569 +  for (i = 0; i < SECTOR_CNT; i++)
1570 +    if (disk_inode->sectors[i]) 
1571 +      {
1572 +        int level = (i >= DIRECT_CNT) + (i >= DIRECT_CNT + INDIRECT_CNT);
1573 +        deallocate_recursive (disk_inode->sectors[i], level); 
1574 +      }
1575 +  cache_unlock (block);
1576 +  deallocate_recursive (inode->sector, 0);
1577  }
1578  
1579  /* Marks INODE to be deleted when it is closed by the last caller who
1580 @@ -187,6 +248,156 @@ inode_remove (struct inode *inode) 
1581    inode->removed = true;
1582  }
1583  
1584 +/* Translates SECTOR_IDX into a sequence of block indexes in
1585 +   OFFSETS and sets *OFFSET_CNT to the number of offsets. */
1586 +static void
1587 +calculate_indices (off_t sector_idx, size_t offsets[], size_t *offset_cnt)
1588 +{
1589 +  /* Handle direct blocks. */
1590 +  if (sector_idx < DIRECT_CNT) 
1591 +    {
1592 +      offsets[0] = sector_idx;
1593 +      *offset_cnt = 1;
1594 +      return;
1595 +    }
1596 +  sector_idx -= DIRECT_CNT;
1597 +
1598 +  /* Handle indirect blocks. */
1599 +  if (sector_idx < PTRS_PER_SECTOR * INDIRECT_CNT)
1600 +    {
1601 +      offsets[0] = DIRECT_CNT + sector_idx / PTRS_PER_SECTOR;
1602 +      offsets[1] = sector_idx % PTRS_PER_SECTOR;
1603 +      *offset_cnt = 2;
1604 +      return;
1605 +    }
1606 +  sector_idx -= PTRS_PER_SECTOR * INDIRECT_CNT;
1607 +
1608 +  /* Handle doubly indirect blocks. */
1609 +  if (sector_idx < DBL_INDIRECT_CNT * PTRS_PER_SECTOR * PTRS_PER_SECTOR)
1610 +    {
1611 +      offsets[0] = (DIRECT_CNT + INDIRECT_CNT
1612 +                    + sector_idx / (PTRS_PER_SECTOR * PTRS_PER_SECTOR));
1613 +      offsets[1] = sector_idx / PTRS_PER_SECTOR;
1614 +      offsets[2] = sector_idx % PTRS_PER_SECTOR;
1615 +      *offset_cnt = 3;
1616 +      return;
1617 +    }
1618 +  NOT_REACHED ();
1619 +}
1620 +
1621 +/* Retrieves the data block for the given byte OFFSET in INODE,
1622 +   setting *DATA_BLOCK to the block.
1623 +   Returns true if successful, false on failure.
1624 +   If ALLOCATE is false, then missing blocks will be successful
1625 +   with *DATA_BLOCk set to a null pointer.
1626 +   If ALLOCATE is true, then missing blocks will be allocated.
1627 +   The block returned will be locked, normally non-exclusively,
1628 +   but a newly allocated block will have an exclusive lock. */
1629 +static bool
1630 +get_data_block (struct inode *inode, off_t offset, bool allocate,
1631 +                struct cache_block **data_block) 
1632 +{
1633 +  disk_sector_t this_level_sector;
1634 +  size_t offsets[3];
1635 +  size_t offset_cnt;
1636 +  size_t level;
1637 +
1638 +  ASSERT (offset >= 0);
1639 +
1640 +  calculate_indices (offset / DISK_SECTOR_SIZE, offsets, &offset_cnt);
1641 +  level = 0;
1642 +  this_level_sector = inode->sector;
1643 +  for (;;) 
1644 +    {
1645 +      struct cache_block *this_level_block;
1646 +      uint32_t *this_level_data;
1647 +
1648 +      struct cache_block *next_level_block;
1649 +
1650 +      /* Check whether the block for the next level is allocated. */
1651 +      this_level_block = cache_lock (this_level_sector, NON_EXCLUSIVE);
1652 +      this_level_data = cache_read (this_level_block);
1653 +      if (this_level_data[offsets[level]] != 0)
1654 +        {
1655 +          /* Yes, it's allocated.  Advance to next level. */
1656 +          this_level_sector = this_level_data[offsets[level]];
1657 +
1658 +          if (++level == offset_cnt) 
1659 +            {
1660 +              /* We hit the data block.
1661 +                 Do read-ahead. */
1662 +              if ((level == 0 && offsets[level] + 1 < DIRECT_CNT)
1663 +                  || (level > 0 && offsets[level] + 1 < PTRS_PER_SECTOR)) 
1664 +                {
1665 +                  uint32_t next_sector = this_level_data[offsets[level] + 1];
1666 +                  if (next_sector && next_sector < disk_size (filesys_disk))
1667 +                    cache_readahead (next_sector); 
1668 +                }
1669 +              cache_unlock (this_level_block);
1670 +
1671 +              /* Return block. */
1672 +              *data_block = cache_lock (this_level_sector, NON_EXCLUSIVE);
1673 +              return true;
1674 +            }
1675 +          cache_unlock (this_level_block);
1676 +          continue;
1677 +        }
1678 +      cache_unlock (this_level_block);
1679 +
1680 +      /* No block is allocated.  Nothing is locked.
1681 +         If we're not allocating new blocks, then this is
1682 +         "success" (with all-zero data). */
1683 +      if (!allocate) 
1684 +        {
1685 +          *data_block = NULL;
1686 +          return true;
1687 +        }
1688 +
1689 +      /* We need to allocate a new block.
1690 +         Grab an exclusive lock on this level's block so we can
1691 +         insert the new block. */
1692 +      this_level_block = cache_lock (this_level_sector, EXCLUSIVE);
1693 +      this_level_data = cache_read (this_level_block);
1694 +
1695 +      /* Since we released this level's block, someone else might
1696 +         have allocated the block in the meantime.  Recheck. */
1697 +      if (this_level_data[offsets[level]] != 0)
1698 +        {
1699 +          cache_unlock (this_level_block);
1700 +          continue;
1701 +        }
1702 +
1703 +      /* Allocate the new block. */
1704 +      if (!free_map_allocate (&this_level_data[offsets[level]]))
1705 +        {
1706 +          cache_unlock (this_level_block);
1707 +          *data_block = NULL;
1708 +          return false;
1709 +        }
1710 +      cache_dirty (this_level_block);
1711 +
1712 +      /* Lock and clear the new block. */
1713 +      next_level_block = cache_lock (this_level_data[offsets[level]],
1714 +                                     EXCLUSIVE);
1715 +      cache_zero (next_level_block);
1716 +
1717 +      /* Release this level's block.  No one else can access the
1718 +         new block yet, because we have an exclusive lock on it. */
1719 +      cache_unlock (this_level_block);
1720 +
1721 +      /* If this is the final level, then return the new block. */
1722 +      if (level == offset_cnt - 1) 
1723 +        {
1724 +          *data_block = next_level_block;
1725 +          return true;
1726 +        }
1727 +
1728 +      /* Otherwise, release the new block and go around again to
1729 +         follow the new pointer. */
1730 +      cache_unlock (next_level_block);
1731 +    }
1732 +}
1733 +
1734  /* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
1735     Returns the number of bytes actually read, which may be less
1736     than SIZE if an error occurs or end of file is reached. */
1737 @@ -195,13 +406,12 @@ inode_read_at (struct inode *inode, void
1738  {
1739    uint8_t *buffer = buffer_;
1740    off_t bytes_read = 0;
1741 -  uint8_t *bounce = NULL;
1742  
1743    while (size > 0) 
1744      {
1745 -      /* Disk sector to read, starting byte offset within sector. */
1746 -      disk_sector_t sector_idx = byte_to_sector (inode, offset);
1747 +      /* Sector to read, starting byte offset within sector, sector data. */
1748        int sector_ofs = offset % DISK_SECTOR_SIZE;
1749 +      struct cache_block *block;
1750  
1751        /* Bytes left in inode, bytes left in sector, lesser of the two. */
1752        off_t inode_left = inode_length (inode) - offset;
1753 @@ -210,26 +420,16 @@ inode_read_at (struct inode *inode, void
1754  
1755        /* Number of bytes to actually copy out of this sector. */
1756        int chunk_size = size < min_left ? size : min_left;
1757 -      if (chunk_size <= 0)
1758 +      if (chunk_size <= 0 || !get_data_block (inode, offset, false, &block))
1759          break;
1760  
1761 -      if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
1762 -        {
1763 -          /* Read full sector directly into caller's buffer. */
1764 -          disk_read (filesys_disk, sector_idx, buffer + bytes_read); 
1765 -        }
1766 +      if (block == NULL) 
1767 +        memset (buffer + bytes_read, 0, chunk_size);
1768        else 
1769          {
1770 -          /* Read sector into bounce buffer, then partially copy
1771 -             into caller's buffer. */
1772 -          if (bounce == NULL) 
1773 -            {
1774 -              bounce = malloc (DISK_SECTOR_SIZE);
1775 -              if (bounce == NULL)
1776 -                break;
1777 -            }
1778 -          disk_read (filesys_disk, sector_idx, bounce);
1779 -          memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
1780 +          const uint8_t *sector_data = cache_read (block);
1781 +          memcpy (buffer + bytes_read, sector_data + sector_ofs, chunk_size);
1782 +          cache_unlock (block);
1783          }
1784        
1785        /* Advance. */
1786 @@ -237,75 +437,82 @@ inode_read_at (struct inode *inode, void
1787        offset += chunk_size;
1788        bytes_read += chunk_size;
1789      }
1790 -  free (bounce);
1791  
1792    return bytes_read;
1793  }
1794  
1795 +/* Extends INODE to be at least LENGTH bytes long. */
1796 +static void
1797 +extend_file (struct inode *inode, off_t length) 
1798 +{
1799 +  if (length > inode_length (inode)) 
1800 +    {
1801 +      struct cache_block *inode_block = cache_lock (inode->sector, EXCLUSIVE);
1802 +      struct inode_disk *disk_inode = cache_read (inode_block);
1803 +      if (length > disk_inode->length) 
1804 +        {
1805 +          disk_inode->length = length;
1806 +          cache_dirty (inode_block);
1807 +        }
1808 +      cache_unlock (inode_block);
1809 +    }
1810 +}
1811 +
1812  /* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
1813     Returns the number of bytes actually written, which may be
1814 -   less than SIZE if end of file is reached or an error occurs.
1815 -   (Normally a write at end of file would extend the inode, but
1816 -   growth is not yet implemented.) */
1817 +   less than SIZE if an error occurs. */
1818  off_t
1819  inode_write_at (struct inode *inode, const void *buffer_, off_t size,
1820                  off_t offset) 
1821  {
1822    const uint8_t *buffer = buffer_;
1823    off_t bytes_written = 0;
1824 -  uint8_t *bounce = NULL;
1825  
1826 -  if (inode->deny_write_cnt)
1827 -    return 0;
1828 +  /* Don't write if writes are denied. */
1829 +  lock_acquire (&inode->deny_write_lock);
1830 +  if (inode->deny_write_cnt) 
1831 +    {
1832 +      lock_release (&inode->deny_write_lock);
1833 +      return 0;
1834 +    }
1835 +  inode->writer_cnt++;
1836 +  lock_release (&inode->deny_write_lock);
1837  
1838    while (size > 0) 
1839      {
1840 -      /* Sector to write, starting byte offset within sector. */
1841 -      disk_sector_t sector_idx = byte_to_sector (inode, offset);
1842 +      /* Sector to write, starting byte offset within sector, sector data. */
1843        int sector_ofs = offset % DISK_SECTOR_SIZE;
1844 +      struct cache_block *block;
1845 +      uint8_t *sector_data;
1846  
1847 -      /* Bytes left in inode, bytes left in sector, lesser of the two. */
1848 -      off_t inode_left = inode_length (inode) - offset;
1849 +      /* Bytes to max inode size, bytes left in sector, lesser of the two. */
1850 +      off_t inode_left = INODE_SPAN - offset;
1851        int sector_left = DISK_SECTOR_SIZE - sector_ofs;
1852        int min_left = inode_left < sector_left ? inode_left : sector_left;
1853  
1854        /* Number of bytes to actually write into this sector. */
1855        int chunk_size = size < min_left ? size : min_left;
1856 -      if (chunk_size <= 0)
1857 -        break;
1858  
1859 -      if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
1860 -        {
1861 -          /* Write full sector directly to disk. */
1862 -          disk_write (filesys_disk, sector_idx, buffer + bytes_written); 
1863 -        }
1864 -      else 
1865 -        {
1866 -          /* We need a bounce buffer. */
1867 -          if (bounce == NULL) 
1868 -            {
1869 -              bounce = malloc (DISK_SECTOR_SIZE);
1870 -              if (bounce == NULL)
1871 -                break;
1872 -            }
1873 +      if (chunk_size <= 0 || !get_data_block (inode, offset, true, &block))
1874 +        break;
1875  
1876 -          /* If the sector contains data before or after the chunk
1877 -             we're writing, then we need to read in the sector
1878 -             first.  Otherwise we start with a sector of all zeros. */
1879 -          if (sector_ofs > 0 || chunk_size < sector_left) 
1880 -            disk_read (filesys_disk, sector_idx, bounce);
1881 -          else
1882 -            memset (bounce, 0, DISK_SECTOR_SIZE);
1883 -          memcpy (bounce + sector_ofs, buffer + bytes_written, chunk_size);
1884 -          disk_write (filesys_disk, sector_idx, bounce); 
1885 -        }
1886 +      sector_data = cache_read (block);
1887 +      memcpy (sector_data + sector_ofs, buffer + bytes_written, chunk_size);
1888 +      cache_dirty (block);
1889 +      cache_unlock (block);
1890  
1891        /* Advance. */
1892        size -= chunk_size;
1893        offset += chunk_size;
1894        bytes_written += chunk_size;
1895      }
1896 -  free (bounce);
1897 +
1898 +  extend_file (inode, offset);
1899 +
1900 +  lock_acquire (&inode->deny_write_lock);
1901 +  if (--inode->writer_cnt == 0)
1902 +    cond_signal (&inode->no_writers_cond, &inode->deny_write_lock);
1903 +  lock_release (&inode->deny_write_lock);
1904  
1905    return bytes_written;
1906  }
1907 @@ -315,8 +522,12 @@ inode_write_at (struct inode *inode, con
1908  void
1909  inode_deny_write (struct inode *inode) 
1910  {
1911 +  lock_acquire (&inode->deny_write_lock);
1912 +  while (inode->writer_cnt > 0)
1913 +    cond_wait (&inode->no_writers_cond, &inode->deny_write_lock);
1914 +  ASSERT (inode->deny_write_cnt < inode->open_cnt);
1915    inode->deny_write_cnt++;
1916 -  ASSERT (inode->deny_write_cnt <= inode->open_cnt);
1917 +  lock_release (&inode->deny_write_lock);
1918  }
1919  
1920  /* Re-enables writes to INODE.
1921 @@ -325,14 +536,47 @@ inode_deny_write (struct inode *inode) 
1922  void
1923  inode_allow_write (struct inode *inode) 
1924  {
1925 +  lock_acquire (&inode->deny_write_lock);
1926    ASSERT (inode->deny_write_cnt > 0);
1927    ASSERT (inode->deny_write_cnt <= inode->open_cnt);
1928    inode->deny_write_cnt--;
1929 +  lock_release (&inode->deny_write_lock);
1930  }
1931  
1932  /* Returns the length, in bytes, of INODE's data. */
1933  off_t
1934  inode_length (const struct inode *inode)
1935  {
1936 -  return inode->data.length;
1937 +  struct cache_block *inode_block = cache_lock (inode->sector, NON_EXCLUSIVE);
1938 +  struct inode_disk *disk_inode = cache_read (inode_block);
1939 +  off_t length = disk_inode->length;
1940 +  cache_unlock (inode_block);
1941 +  return length;
1942 +}
1943 +
1944 +/* Returns the number of openers. */
1945 +int
1946 +inode_open_cnt (const struct inode *inode) 
1947 +{
1948 +  int open_cnt;
1949 +  
1950 +  lock_acquire (&open_inodes_lock);
1951 +  open_cnt = inode->open_cnt;
1952 +  lock_release (&open_inodes_lock);
1953 +
1954 +  return open_cnt;
1955 +}
1956 +
1957 +/* Locks INODE. */
1958 +void
1959 +inode_lock (struct inode *inode) 
1960 +{
1961 +  lock_acquire (&inode->lock);
1962 +}
1963 +
1964 +/* Releases INODE's lock. */
1965 +void
1966 +inode_unlock (struct inode *inode) 
1967 +{
1968 +  lock_release (&inode->lock);
1969  }
1970 Index: src/filesys/inode.h
1971 diff -u src/filesys/inode.h~ src/filesys/inode.h
1972 --- src/filesys/inode.h~
1973 +++ src/filesys/inode.h
1974 @@ -7,11 +7,19 @@
1975  
1976  struct bitmap;
1977  
1978 +/* Type of an inode. */
1979 +enum inode_type 
1980 +  {
1981 +    FILE_INODE,         /* Ordinary file. */
1982 +    DIR_INODE           /* Directory. */
1983 +  };
1984 +
1985  void inode_init (void);
1986 -bool inode_create (disk_sector_t, off_t);
1987 +struct inode *inode_create (disk_sector_t, enum inode_type);
1988  struct inode *inode_open (disk_sector_t);
1989  struct inode *inode_reopen (struct inode *);
1990 +enum inode_type inode_get_type (const struct inode *);
1991  disk_sector_t inode_get_inumber (const struct inode *);
1992  void inode_close (struct inode *);
1993  void inode_remove (struct inode *);
1994  off_t inode_read_at (struct inode *, void *, off_t size, off_t offset);
1995 @@ -18,5 +27,8 @@ off_t inode_write_at (struct inode *, co
1996  void inode_deny_write (struct inode *);
1997  void inode_allow_write (struct inode *);
1998  off_t inode_length (const struct inode *);
1999 +int inode_open_cnt (const struct inode *);
2000 +void inode_lock (struct inode *);
2001 +void inode_unlock (struct inode *);
2002  
2003  #endif /* filesys/inode.h */
2004 Index: src/threads/init.c
2005 diff -u src/threads/init.c~ src/threads/init.c
2006 --- src/threads/init.c~
2007 +++ src/threads/init.c
2008 @@ -33,6 +33,8 @@
2009  #include "filesys/filesys.h"
2010  #include "filesys/fsutil.h"
2011  #endif
2012 +#include "vm/frame.h"
2013 +#include "vm/swap.h"
2014  
2015  /* Amount of physical memory, in 4 kB pages. */
2016  size_t ram_pages;
2017 @@ -124,6 +126,9 @@ main (void)
2018    filesys_init (format_filesys);
2019  #endif
2020  
2021 +  frame_init ();
2022 +  swap_init ();
2023 +
2024    printf ("Boot complete.\n");
2025    
2026    /* Run actions specified on kernel command line. */
2027 Index: src/threads/interrupt.c
2028 diff -u src/threads/interrupt.c~ src/threads/interrupt.c
2029 --- src/threads/interrupt.c~
2030 +++ src/threads/interrupt.c
2031 @@ -354,6 +354,8 @@ intr_handler (struct intr_frame *frame) 
2032        in_external_intr = true;
2033        yield_on_return = false;
2034      }
2035 +  else 
2036 +    thread_current ()->user_esp = frame->esp;
2037  
2038    /* Invoke the interrupt's handler.
2039       If there is no handler, invoke the unexpected interrupt
2040 Index: src/threads/thread.c
2041 diff -u src/threads/thread.c~ src/threads/thread.c
2042 --- src/threads/thread.c~
2043 +++ src/threads/thread.c
2044 @@ -13,6 +13,7 @@
2045  #include "threads/vaddr.h"
2046  #ifdef USERPROG
2047  #include "userprog/process.h"
2048 +#include "userprog/syscall.h"
2049  #endif
2050  
2051  /* Random value for struct thread's `magic' member.
2052 @@ -55,7 +56,8 @@ static void kernel_thread (thread_func *
2053  static void idle (void *aux UNUSED);
2054  static struct thread *running_thread (void);
2055  static struct thread *next_thread_to_run (void);
2056 -static void init_thread (struct thread *, const char *name, int priority);
2057 +static void init_thread (struct thread *, const char *name, int priority,
2058 +                         tid_t);
2059  static bool is_thread (struct thread *) UNUSED;
2060  static void *alloc_frame (struct thread *, size_t size);
2061  static void schedule (void);
2062 @@ -82,9 +84,8 @@ thread_init (void) 
2063  
2064    /* Set up a thread structure for the running thread. */
2065    initial_thread = running_thread ();
2066 -  init_thread (initial_thread, "main", PRI_DEFAULT);
2067 +  init_thread (initial_thread, "main", PRI_DEFAULT, 0);
2068    initial_thread->status = THREAD_RUNNING;
2069 -  initial_thread->tid = allocate_tid ();
2070  }
2071  
2072  /* Starts preemptive thread scheduling by enabling interrupts.
2073 @@ -159,8 +160,8 @@ thread_create (const char *name, int pri
2074      return TID_ERROR;
2075  
2076    /* Initialize thread. */
2077 -  init_thread (t, name, priority);
2078 -  tid = t->tid = allocate_tid ();
2079 +  init_thread (t, name, priority, allocate_tid ());
2080 +  tid = t->tid;
2081  
2082    /* Stack frame for kernel_thread(). */
2083    kf = alloc_frame (t, sizeof *kf);
2084 @@ -253,16 +254,19 @@ thread_tid (void) 
2085  void
2086  thread_exit (void) 
2087  {
2088 +  struct thread *t = thread_current ();
2089 +
2090    ASSERT (!intr_context ());
2091  
2092 +  syscall_exit ();
2093  #ifdef USERPROG
2094    process_exit ();
2095  #endif
2096  
2097    /* Just set our status to dying and schedule another process.
2098       We will be destroyed during the call to schedule_tail(). */
2099    intr_disable ();
2100 -  thread_current ()->status = THREAD_DYING;
2101 +  t->status = THREAD_DYING;
2102    schedule ();
2103    NOT_REACHED ();
2104  }
2105 @@ -406,17 +410,29 @@ is_thread (struct thread *t)
2106  /* Does basic initialization of T as a blocked thread named
2107     NAME. */
2108  static void
2109 -init_thread (struct thread *t, const char *name, int priority)
2110 +init_thread (struct thread *t, const char *name, int priority, tid_t tid)
2111  {
2112    ASSERT (t != NULL);
2113    ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
2114    ASSERT (name != NULL);
2115  
2116    memset (t, 0, sizeof *t);
2117 +  t->tid = tid;
2118    t->status = THREAD_BLOCKED;
2119    strlcpy (t->name, name, sizeof t->name);
2120    t->stack = (uint8_t *) t + PGSIZE;
2121    t->priority = priority;
2122 +  t->exit_code = -1;
2123 +  t->wait_status = NULL;
2124 +  list_init (&t->children);
2125 +  sema_init (&t->timer_sema, 0);
2126 +  t->pagedir = NULL;
2127 +  t->pages = NULL;
2128 +  t->bin_file = NULL;
2129 +  list_init (&t->fds);
2130 +  list_init (&t->mappings);
2131 +  t->next_handle = 2;
2132 +  t->wd = NULL;
2133    t->magic = THREAD_MAGIC;
2134  }
2135  
2136 Index: src/threads/thread.h
2137 diff -u src/threads/thread.h~ src/threads/thread.h
2138 --- src/threads/thread.h~
2139 +++ src/threads/thread.h
2140 @@ -2,8 +2,10 @@
2141  #define THREADS_THREAD_H
2142  
2143  #include <debug.h>
2144 +#include <hash.h>
2145  #include <list.h>
2146  #include <stdint.h>
2147 +#include "threads/synch.h"
2148  
2149  /* States in a thread's life cycle. */
2150  enum thread_status
2151 @@ -89,18 +91,50 @@ struct thread
2152      uint8_t *stack;                     /* Saved stack pointer. */
2153      int priority;                       /* Priority. */
2154  
2155 +    /* Owned by process.c. */
2156 +    int exit_code;                      /* Exit code. */
2157 +    struct wait_status *wait_status;    /* This process's completion status. */
2158 +    struct list children;               /* Completion status of children. */
2159 +
2160      /* Shared between thread.c and synch.c. */
2161      struct list_elem elem;              /* List element. */
2162  
2163 -#ifdef USERPROG
2164 +    /* Alarm clock. */
2165 +    int64_t wakeup_time;                /* Time to wake this thread up. */
2166 +    struct list_elem timer_elem;        /* Element in timer_wait_list. */
2167 +    struct semaphore timer_sema;        /* Semaphore. */
2168 +
2169      /* Owned by userprog/process.c. */
2170      uint32_t *pagedir;                  /* Page directory. */
2171 -#endif
2172 +    struct hash *pages;                 /* Page table. */
2173 +    struct file *bin_file;              /* The binary executable. */
2174 +
2175 +    /* Owned by syscall.c. */
2176 +    struct list fds;                    /* List of file descriptors. */
2177 +    struct list mappings;               /* Memory-mapped files. */
2178 +    int next_handle;                    /* Next handle value. */
2179 +    void *user_esp;                     /* User's stack pointer. */
2180 +    struct dir *wd;                     /* Working directory. */
2181  
2182      /* Owned by thread.c. */
2183      unsigned magic;                     /* Detects stack overflow. */
2184    };
2185  
2186 +/* Tracks the completion of a process.
2187 +   Reference held by both the parent, in its `children' list,
2188 +   and by the child, in its `wait_status' pointer. */
2189 +struct wait_status
2190 +  {
2191 +    struct list_elem elem;              /* `children' list element. */
2192 +    struct lock lock;                   /* Protects ref_cnt. */
2193 +    int ref_cnt;                        /* 2=child and parent both alive,
2194 +                                           1=either child or parent alive,
2195 +                                           0=child and parent both dead. */
2196 +    tid_t tid;                          /* Child thread id. */
2197 +    int exit_code;                      /* Child exit code, if dead. */
2198 +    struct semaphore dead;              /* 1=child alive, 0=child dead. */
2199 +  };
2200 +
2201  void thread_init (void);
2202  void thread_start (void);
2203  
2204 Index: src/userprog/exception.c
2205 diff -u src/userprog/exception.c~ src/userprog/exception.c
2206 --- src/userprog/exception.c~
2207 +++ src/userprog/exception.c
2208 @@ -4,6 +4,7 @@
2209  #include "userprog/gdt.h"
2210  #include "threads/interrupt.h"
2211  #include "threads/thread.h"
2212 +#include "vm/page.h"
2213  
2214  /* Number of page faults processed. */
2215  static long long page_fault_cnt;
2216 @@ -148,9 +149,14 @@ page_fault (struct intr_frame *f) 
2217    write = (f->error_code & PF_W) != 0;
2218    user = (f->error_code & PF_U) != 0;
2219  
2220 -  /* To implement virtual memory, delete the rest of the function
2221 -     body, and replace it with code that brings in the page to
2222 -     which fault_addr refers. */
2223 +  /* Allow the pager to try to handle it. */
2224 +  if (user && not_present)
2225 +    {
2226 +      if (!page_in (fault_addr))
2227 +        thread_exit ();
2228 +      return;
2229 +    }
2230 +
2231    printf ("Page fault at %p: %s error %s page in %s context.\n",
2232            fault_addr,
2233            not_present ? "not present" : "rights violation",
2234 Index: src/userprog/pagedir.c
2235 diff -u src/userprog/pagedir.c~ src/userprog/pagedir.c
2236 --- src/userprog/pagedir.c~
2237 +++ src/userprog/pagedir.c
2238 @@ -35,15 +35,7 @@ pagedir_destroy (uint32_t *pd) 
2239    ASSERT (pd != base_page_dir);
2240    for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
2241      if (*pde & PTE_P) 
2242 -      {
2243 -        uint32_t *pt = pde_get_pt (*pde);
2244 -        uint32_t *pte;
2245 -        
2246 -        for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
2247 -          if (*pte & PTE_P) 
2248 -            palloc_free_page (pte_get_page (*pte));
2249 -        palloc_free_page (pt);
2250 -      }
2251 +      palloc_free_page (pde_get_pt (*pde));
2252    palloc_free_page (pd);
2253  }
2254  
2255 Index: src/userprog/process.c
2256 diff -u src/userprog/process.c~ src/userprog/process.c
2257 --- src/userprog/process.c~
2258 +++ src/userprog/process.c
2259 @@ -14,12 +14,27 @@
2260  #include "threads/flags.h"
2261  #include "threads/init.h"
2262  #include "threads/interrupt.h"
2263 +#include "threads/malloc.h"
2264  #include "threads/palloc.h"
2265  #include "threads/thread.h"
2266  #include "threads/vaddr.h"
2267 +#include "vm/page.h"
2268 +#include "vm/frame.h"
2269  
2270  static thread_func execute_thread NO_RETURN;
2271 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
2272 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
2273 +
2274 +/* Data structure shared between process_execute() in the
2275 +   invoking thread and execute_thread() in the newly invoked
2276 +   thread. */
2277 +struct exec_info 
2278 +  {
2279 +    const char *file_name;              /* Program to load. */
2280 +    struct semaphore load_done;         /* "Up"ed when loading complete. */
2281 +    struct wait_status *wait_status;    /* Child process. */
2282 +    struct dir *wd;                     /* Working directory. */
2283 +    bool success;                       /* Program successfully loaded? */
2284 +  };
2285  
2286  /* Starts a new thread running a user program loaded from
2287     FILENAME.  The new thread may be scheduled (and may even exit)
2288 @@ -28,41 +43,78 @@ static bool load (const char *cmdline, v
2289  tid_t
2290  process_execute (const char *file_name) 
2291  {
2292 -  char *fn_copy;
2293 +  struct dir *wd = thread_current ()->wd;
2294 +  struct exec_info exec;
2295 +  char thread_name[16];
2296 +  char *save_ptr;
2297    tid_t tid;
2298  
2299 -  /* Make a copy of FILE_NAME.
2300 -     Otherwise there's a race between the caller and load(). */
2301 -  fn_copy = palloc_get_page (0);
2302 -  if (fn_copy == NULL)
2303 +  /* Initialize exec_info. */
2304 +  exec.file_name = file_name;
2305 +  exec.wd = wd != NULL ? dir_reopen (wd) : dir_open_root ();
2306 +  if (exec.wd == NULL)
2307      return TID_ERROR;
2308 -  strlcpy (fn_copy, file_name, PGSIZE);
2309 +  sema_init (&exec.load_done, 0);
2310  
2311    /* Create a new thread to execute FILE_NAME. */
2312 -  tid = thread_create (file_name, PRI_DEFAULT, execute_thread, fn_copy);
2313 -  if (tid == TID_ERROR)
2314 -    palloc_free_page (fn_copy); 
2315 +  strlcpy (thread_name, file_name, sizeof thread_name);
2316 +  strtok_r (thread_name, " ", &save_ptr);
2317 +  tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
2318 +  if (tid != TID_ERROR)
2319 +    {
2320 +      sema_down (&exec.load_done);
2321 +      if (exec.success)
2322 +        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
2323 +      else 
2324 +        {
2325 +          tid = TID_ERROR;
2326 +          /* Don't close exec.wd; child process will have done so. */
2327 +        }
2328 +    }
2329 +  else
2330 +    dir_close (exec.wd);
2331 +
2332    return tid;
2333  }
2334  
2335  /* A thread function that loads a user process and starts it
2336     running. */
2337  static void
2338 -execute_thread (void *file_name_)
2339 +execute_thread (void *exec_)
2340  {
2341 -  char *file_name = file_name_;
2342 +  struct exec_info *exec = exec_;
2343    struct intr_frame if_;
2344    bool success;
2345  
2346 +  thread_current ()->wd = exec->wd;
2347 +
2348    /* Initialize interrupt frame and load executable. */
2349    memset (&if_, 0, sizeof if_);
2350    if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
2351    if_.cs = SEL_UCSEG;
2352    if_.eflags = FLAG_IF | FLAG_MBS;
2353 -  success = load (file_name, &if_.eip, &if_.esp);
2354 +  success = load (exec->file_name, &if_.eip, &if_.esp);
2355  
2356 -  /* If load failed, quit. */
2357 -  palloc_free_page (file_name);
2358 +  /* Allocate wait_status. */
2359 +  if (success)
2360 +    {
2361 +      exec->wait_status = thread_current ()->wait_status
2362 +        = malloc (sizeof *exec->wait_status);
2363 +      success = exec->wait_status != NULL; 
2364 +    }
2365 +
2366 +  /* Initialize wait_status. */
2367 +  if (success) 
2368 +    {
2369 +      lock_init (&exec->wait_status->lock);
2370 +      exec->wait_status->ref_cnt = 2;
2371 +      exec->wait_status->tid = thread_current ()->tid;
2372 +      sema_init (&exec->wait_status->dead, 0);
2373 +    }
2374 +  
2375 +  /* Notify parent thread and clean up. */
2376 +  exec->success = success;
2377 +  sema_up (&exec->load_done);
2378    if (!success) 
2379      thread_exit ();
2380  
2381 @@ -76,18 +128,47 @@ execute_thread (void *file_name_)
2382    NOT_REACHED ();
2383  }
2384  
2385 +/* Releases one reference to CS and, if it is now unreferenced,
2386 +   frees it. */
2387 +static void
2388 +release_child (struct wait_status *cs) 
2389 +{
2390 +  int new_ref_cnt;
2391 +  
2392 +  lock_acquire (&cs->lock);
2393 +  new_ref_cnt = --cs->ref_cnt;
2394 +  lock_release (&cs->lock);
2395 +
2396 +  if (new_ref_cnt == 0)
2397 +    free (cs);
2398 +}
2399 +
2400  /* Waits for thread TID to die and returns its exit status.  If
2401     it was terminated by the kernel (i.e. killed due to an
2402     exception), returns -1.  If TID is invalid or if it was not a
2403     child of the calling process, or if process_wait() has already
2404     been successfully called for the given TID, returns -1
2405 -   immediately, without waiting.
2406 -
2407 -   This function will be implemented in problem 2-2.  For now, it
2408 -   does nothing. */
2409 +   immediately, without waiting. */
2410  int
2411 -process_wait (tid_t child_tid UNUSED) 
2412 +process_wait (tid_t child_tid) 
2413  {
2414 +  struct thread *cur = thread_current ();
2415 +  struct list_elem *e;
2416 +
2417 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
2418 +       e = list_next (e)) 
2419 +    {
2420 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
2421 +      if (cs->tid == child_tid) 
2422 +        {
2423 +          int exit_code;
2424 +          list_remove (e);
2425 +          sema_down (&cs->dead);
2426 +          exit_code = cs->exit_code;
2427 +          release_child (cs);
2428 +          return exit_code;
2429 +        }
2430 +    }
2431    return -1;
2432  }
2433  
2434 @@ -96,8 +177,35 @@ void
2435  process_exit (void)
2436  {
2437    struct thread *cur = thread_current ();
2438 +  struct list_elem *e, *next;
2439    uint32_t *pd;
2440  
2441 +  printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
2442 +
2443 +  /* Notify parent that we're dead. */
2444 +  if (cur->wait_status != NULL) 
2445 +    {
2446 +      struct wait_status *cs = cur->wait_status;
2447 +      cs->exit_code = cur->exit_code;
2448 +      sema_up (&cs->dead);
2449 +      release_child (cs);
2450 +    }
2451 +
2452 +  /* Free entries of children list. */
2453 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
2454 +       e = next) 
2455 +    {
2456 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
2457 +      next = list_remove (e);
2458 +      release_child (cs);
2459 +    }
2460 +
2461 +  /* Destroy the page hash table. */
2462 +  page_exit ();
2463 +  
2464 +  /* Close executable (and allow writes). */
2465 +  file_close (cur->bin_file);
2466 +
2467    /* Destroy the current process's page directory and switch back
2468       to the kernel-only page directory. */
2469    pd = cur->pagedir;
2470 @@ -194,7 +302,7 @@ struct Elf32_Phdr
2471  #define PF_W 2          /* Writable. */
2472  #define PF_R 4          /* Readable. */
2473  
2474 -static bool setup_stack (void **esp);
2475 +static bool setup_stack (const char *cmd_line, void **esp);
2476  static bool validate_segment (const struct Elf32_Phdr *, struct file *);
2477  static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
2478                            uint32_t read_bytes, uint32_t zero_bytes,
2479 @@ -205,13 +313,15 @@ static bool load_segment (struct file *f
2480     and its initial stack pointer into *ESP.
2481     Returns true if successful, false otherwise. */
2482  bool
2483 -load (const char *file_name, void (**eip) (void), void **esp) 
2484 +load (const char *cmd_line, void (**eip) (void), void **esp) 
2485  {
2486    struct thread *t = thread_current ();
2487 +  char file_name[NAME_MAX + 2];
2488    struct Elf32_Ehdr ehdr;
2489    struct file *file = NULL;
2490    off_t file_ofs;
2491    bool success = false;
2492 +  char *cp;
2493    int i;
2494  
2495    /* Allocate and activate page directory. */
2496 @@ -220,13 +330,28 @@ load (const char *file_name, void (**eip
2497      goto done;
2498    process_activate ();
2499  
2500 +  /* Create page hash table. */
2501 +  t->pages = malloc (sizeof *t->pages);
2502 +  if (t->pages == NULL)
2503 +    goto done;
2504 +  hash_init (t->pages, page_hash, page_less, NULL);
2505 +
2506 +  /* Extract file_name from command line. */
2507 +  while (*cmd_line == ' ')
2508 +    cmd_line++;
2509 +  strlcpy (file_name, cmd_line, sizeof file_name);
2510 +  cp = strchr (file_name, ' ');
2511 +  if (cp != NULL)
2512 +    *cp = '\0';
2513 +
2514    /* Open executable file. */
2515 -  file = filesys_open (file_name);
2516 +  t->bin_file = file = file_open (filesys_open (file_name));
2517    if (file == NULL) 
2518      {
2519        printf ("load: %s: open failed\n", file_name);
2520        goto done; 
2521      }
2522 +  file_deny_write (file);
2523  
2524    /* Read and verify executable header. */
2525    if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
2526 @@ -301,7 +426,7 @@ load (const char *file_name, void (**eip
2527      }
2528  
2529    /* Set up stack. */
2530 -  if (!setup_stack (esp))
2531 +  if (!setup_stack (cmd_line, esp))
2532      goto done;
2533  
2534    /* Start address. */
2535 @@ -311,14 +436,11 @@ load (const char *file_name, void (**eip
2536  
2537   done:
2538    /* We arrive here whether the load is successful or not. */
2539 -  file_close (file);
2540    return success;
2541  }
2542  \f
2543  /* load() helpers. */
2544  
2545 -static bool install_page (void *upage, void *kpage, bool writable);
2546 -
2547  /* Checks whether PHDR describes a valid, loadable segment in
2548     FILE and returns true if so, false otherwise. */
2549  static bool
2550 @@ -386,79 +508,127 @@ load_segment (struct file *file, off_t o
2551    ASSERT (pg_ofs (upage) == 0);
2552    ASSERT (ofs % PGSIZE == 0);
2553  
2554 -  file_seek (file, ofs);
2555    while (read_bytes > 0 || zero_bytes > 0) 
2556      {
2557 -      /* Calculate how to fill this page.
2558 -         We will read PAGE_READ_BYTES bytes from FILE
2559 -         and zero the final PAGE_ZERO_BYTES bytes. */
2560        size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
2561        size_t page_zero_bytes = PGSIZE - page_read_bytes;
2562 -
2563 -      /* Get a page of memory. */
2564 -      uint8_t *kpage = palloc_get_page (PAL_USER);
2565 -      if (kpage == NULL)
2566 +      struct page *p = page_allocate (upage, !writable);
2567 +      if (p == NULL)
2568          return false;
2569 -
2570 -      /* Load this page. */
2571 -      if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes)
2572 -        {
2573 -          palloc_free_page (kpage);
2574 -          return false; 
2575 -        }
2576 -      memset (kpage + page_read_bytes, 0, page_zero_bytes);
2577 -
2578 -      /* Add the page to the process's address space. */
2579 -      if (!install_page (upage, kpage, writable)) 
2580 +      if (page_read_bytes > 0) 
2581          {
2582 -          palloc_free_page (kpage);
2583 -          return false; 
2584 +          p->file = file;
2585 +          p->file_offset = ofs;
2586 +          p->file_bytes = page_read_bytes;
2587          }
2588 -
2589 -      /* Advance. */
2590        read_bytes -= page_read_bytes;
2591        zero_bytes -= page_zero_bytes;
2592 +      ofs += page_read_bytes;
2593        upage += PGSIZE;
2594      }
2595    return true;
2596  }
2597  
2598 -/* Create a minimal stack by mapping a zeroed page at the top of
2599 -   user virtual memory. */
2600 +/* Reverse the order of the ARGC pointers to char in ARGV. */
2601 +static void
2602 +reverse (int argc, char **argv) 
2603 +{
2604 +  for (; argc > 1; argc -= 2, argv++) 
2605 +    {
2606 +      char *tmp = argv[0];
2607 +      argv[0] = argv[argc - 1];
2608 +      argv[argc - 1] = tmp;
2609 +    }
2610 +}
2611
2612 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
2613 +   page-relative stack pointer is *OFS, and then adjusts *OFS
2614 +   appropriately.  The bytes pushed are rounded to a 32-bit
2615 +   boundary.
2616 +
2617 +   If successful, returns a pointer to the newly pushed object.
2618 +   On failure, returns a null pointer. */
2619 +static void *
2620 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
2621 +{
2622 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
2623 +  if (*ofs < padsize)
2624 +    return NULL;
2625 +
2626 +  *ofs -= padsize;
2627 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
2628 +  return kpage + *ofs + (padsize - size);
2629 +}
2630 +
2631 +/* Sets up command line arguments in KPAGE, which will be mapped
2632 +   to UPAGE in user space.  The command line arguments are taken
2633 +   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
2634 +   stack pointer for the process. */
2635  static bool
2636 -setup_stack (void **esp) 
2637 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
2638 +               void **esp) 
2639  {
2640 -  uint8_t *kpage;
2641 -  bool success = false;
2642 +  size_t ofs = PGSIZE;
2643 +  char *const null = NULL;
2644 +  char *cmd_line_copy;
2645 +  char *karg, *saveptr;
2646 +  int argc;
2647 +  char **argv;
2648 +
2649 +  /* Push command line string. */
2650 +  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
2651 +  if (cmd_line_copy == NULL)
2652 +    return false;
2653  
2654 -  kpage = palloc_get_page (PAL_USER | PAL_ZERO);
2655 -  if (kpage != NULL) 
2656 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
2657 +    return false;
2658 +
2659 +  /* Parse command line into arguments
2660 +     and push them in reverse order. */
2661 +  argc = 0;
2662 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
2663 +       karg = strtok_r (NULL, " ", &saveptr))
2664      {
2665 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
2666 -      if (success)
2667 -        *esp = PHYS_BASE;
2668 -      else
2669 -        palloc_free_page (kpage);
2670 +      void *uarg = upage + (karg - (char *) kpage);
2671 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
2672 +        return false;
2673 +      argc++;
2674      }
2675 -  return success;
2676 +
2677 +  /* Reverse the order of the command line arguments. */
2678 +  argv = (char **) (upage + ofs);
2679 +  reverse (argc, (char **) (kpage + ofs));
2680 +
2681 +  /* Push argv, argc, "return address". */
2682 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
2683 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
2684 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
2685 +    return false;
2686 +
2687 +  /* Set initial stack pointer. */
2688 +  *esp = upage + ofs;
2689 +  return true;
2690  }
2691  
2692 -/* Adds a mapping from user virtual address UPAGE to kernel
2693 -   virtual address KPAGE to the page table.
2694 -   If WRITABLE is true, the user process may modify the page;
2695 -   otherwise, it is read-only.
2696 -   UPAGE must not already be mapped.
2697 -   KPAGE should probably be a page obtained from the user pool
2698 -   with palloc_get_page().
2699 -   Returns true on success, false if UPAGE is already mapped or
2700 -   if memory allocation fails. */
2701 +/* Create a minimal stack for T by mapping a page at the
2702 +   top of user virtual memory.  Fills in the page using CMD_LINE
2703 +   and sets *ESP to the stack pointer. */
2704  static bool
2705 -install_page (void *upage, void *kpage, bool writable)
2706 +setup_stack (const char *cmd_line, void **esp) 
2707  {
2708 -  struct thread *t = thread_current ();
2709 -
2710 -  /* Verify that there's not already a page at that virtual
2711 -     address, then map our page there. */
2712 -  return (pagedir_get_page (t->pagedir, upage) == NULL
2713 -          && pagedir_set_page (t->pagedir, upage, kpage, writable));
2714 +  struct page *page = page_allocate (((uint8_t *) PHYS_BASE) - PGSIZE, false);
2715 +  if (page != NULL) 
2716 +    {
2717 +      page->frame = frame_alloc_and_lock (page);
2718 +      if (page->frame != NULL)
2719 +        {
2720 +          bool ok;
2721 +          page->read_only = false;
2722 +          page->private = false;
2723 +          ok = init_cmd_line (page->frame->base, page->addr, cmd_line, esp);
2724 +          frame_unlock (page->frame);
2725 +          return ok;
2726 +        }
2727 +    }
2728 +  return false;
2729  }
2730 Index: src/userprog/syscall.c
2731 diff -u src/userprog/syscall.c~ src/userprog/syscall.c
2732 --- src/userprog/syscall.c~
2733 +++ src/userprog/syscall.c
2734 @@ -1,20 +1,684 @@
2735  #include "userprog/syscall.h"
2736  #include <stdio.h>
2737 +#include <string.h>
2738  #include <syscall-nr.h>
2739 +#include "userprog/process.h"
2740 +#include "userprog/pagedir.h"
2741 +#include "devices/kbd.h"
2742 +#include "filesys/directory.h"
2743 +#include "filesys/filesys.h"
2744 +#include "filesys/file.h"
2745 +#include "threads/init.h"
2746  #include "threads/interrupt.h"
2747 +#include "threads/malloc.h"
2748 +#include "threads/palloc.h"
2749  #include "threads/thread.h"
2750 -
2751 +#include "threads/vaddr.h"
2752 +#include "vm/page.h"
2753
2754
2755 +static int sys_halt (void);
2756 +static int sys_exit (int status);
2757 +static int sys_exec (const char *ufile);
2758 +static int sys_wait (tid_t);
2759 +static int sys_create (const char *ufile, unsigned initial_size);
2760 +static int sys_remove (const char *ufile);
2761 +static int sys_open (const char *ufile);
2762 +static int sys_filesize (int handle);
2763 +static int sys_read (int handle, void *udst_, unsigned size);
2764 +static int sys_write (int handle, void *usrc_, unsigned size);
2765 +static int sys_seek (int handle, unsigned position);
2766 +static int sys_tell (int handle);
2767 +static int sys_close (int handle);
2768 +static int sys_mmap (int handle, void *addr);
2769 +static int sys_munmap (int mapping);
2770 +static int sys_chdir (const char *udir);
2771 +static int sys_mkdir (const char *udir);
2772 +static int sys_readdir (int handle, char *name);
2773 +static int sys_isdir (int handle);
2774 +static int sys_inumber (int handle);
2775
2776  static void syscall_handler (struct intr_frame *);
2777 -
2778 +static void copy_in (void *, const void *, size_t);
2779
2780  void
2781  syscall_init (void) 
2782  {
2783    intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
2784  }
2785
2786 +/* System call handler. */
2787 +static void
2788 +syscall_handler (struct intr_frame *f) 
2789 +{
2790 +  typedef int syscall_function (int, int, int);
2791 +
2792 +  /* A system call. */
2793 +  struct syscall 
2794 +    {
2795 +      size_t arg_cnt;           /* Number of arguments. */
2796 +      syscall_function *func;   /* Implementation. */
2797 +    };
2798 +
2799 +  /* Table of system calls. */
2800 +  static const struct syscall syscall_table[] =
2801 +    {
2802 +      {0, (syscall_function *) sys_halt},
2803 +      {1, (syscall_function *) sys_exit},
2804 +      {1, (syscall_function *) sys_exec},
2805 +      {1, (syscall_function *) sys_wait},
2806 +      {2, (syscall_function *) sys_create},
2807 +      {1, (syscall_function *) sys_remove},
2808 +      {1, (syscall_function *) sys_open},
2809 +      {1, (syscall_function *) sys_filesize},
2810 +      {3, (syscall_function *) sys_read},
2811 +      {3, (syscall_function *) sys_write},
2812 +      {2, (syscall_function *) sys_seek},
2813 +      {1, (syscall_function *) sys_tell},
2814 +      {1, (syscall_function *) sys_close},
2815 +      {2, (syscall_function *) sys_mmap},
2816 +      {1, (syscall_function *) sys_munmap},
2817 +      {1, (syscall_function *) sys_chdir},
2818 +      {1, (syscall_function *) sys_mkdir},
2819 +      {2, (syscall_function *) sys_readdir},
2820 +      {1, (syscall_function *) sys_isdir},
2821 +      {1, (syscall_function *) sys_inumber},
2822 +    };
2823 +
2824 +  const struct syscall *sc;
2825 +  unsigned call_nr;
2826 +  int args[3];
2827  
2828 +  /* Get the system call. */
2829 +  copy_in (&call_nr, f->esp, sizeof call_nr);
2830 +  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
2831 +    thread_exit ();
2832 +  sc = syscall_table + call_nr;
2833 +
2834 +  /* Get the system call arguments. */
2835 +  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
2836 +  memset (args, 0, sizeof args);
2837 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
2838 +
2839 +  /* Execute the system call,
2840 +     and set the return value. */
2841 +  f->eax = sc->func (args[0], args[1], args[2]);
2842 +}
2843
2844 +/* Copies SIZE bytes from user address USRC to kernel address
2845 +   DST.
2846 +   Call thread_exit() if any of the user accesses are invalid. */
2847  static void
2848 -syscall_handler (struct intr_frame *f UNUSED) 
2849 +copy_in (void *dst_, const void *usrc_, size_t size) 
2850  {
2851 -  printf ("system call!\n");
2852 +  uint8_t *dst = dst_;
2853 +  const uint8_t *usrc = usrc_;
2854 +
2855 +  while (size > 0) 
2856 +    {
2857 +      size_t chunk_size = PGSIZE - pg_ofs (usrc);
2858 +      if (chunk_size > size)
2859 +        chunk_size = size;
2860 +      
2861 +      if (!page_lock (usrc, false))
2862 +        thread_exit ();
2863 +      memcpy (dst, usrc, chunk_size);
2864 +      page_unlock (usrc);
2865 +
2866 +      dst += chunk_size;
2867 +      usrc += chunk_size;
2868 +      size -= chunk_size;
2869 +    }
2870 +}
2871
2872 +/* Copies SIZE bytes from kernel address SRC to user address
2873 +   UDST.
2874 +   Call thread_exit() if any of the user accesses are invalid. */
2875 +static void
2876 +copy_out (void *udst_, const void *src_, size_t size) 
2877 +{
2878 +  uint8_t *udst = udst_;
2879 +  const uint8_t *src = src_;
2880 +
2881 +  while (size > 0) 
2882 +    {
2883 +      size_t chunk_size = PGSIZE - pg_ofs (udst);
2884 +      if (chunk_size > size)
2885 +        chunk_size = size;
2886 +      
2887 +      if (!page_lock (udst, false))
2888 +        thread_exit ();
2889 +      memcpy (udst, src, chunk_size);
2890 +      page_unlock (udst);
2891 +
2892 +      udst += chunk_size;
2893 +      src += chunk_size;
2894 +      size -= chunk_size;
2895 +    }
2896 +}
2897
2898 +/* Creates a copy of user string US in kernel memory
2899 +   and returns it as a page that must be freed with
2900 +   palloc_free_page().
2901 +   Truncates the string at PGSIZE bytes in size.
2902 +   Call thread_exit() if any of the user accesses are invalid. */
2903 +static char *
2904 +copy_in_string (const char *us) 
2905 +{
2906 +  char *ks;
2907 +  char *upage;
2908 +  size_t length;
2909
2910 +  ks = palloc_get_page (0);
2911 +  if (ks == NULL) 
2912 +    thread_exit ();
2913 +
2914 +  length = 0;
2915 +  for (;;) 
2916 +    {
2917 +      upage = pg_round_down (us);
2918 +      if (!page_lock (upage, false))
2919 +        goto lock_error;
2920 +
2921 +      for (; us < upage + PGSIZE; us++) 
2922 +        {
2923 +          ks[length++] = *us;
2924 +          if (*us == '\0') 
2925 +            {
2926 +              page_unlock (upage);
2927 +              return ks; 
2928 +            }
2929 +          else if (length >= PGSIZE) 
2930 +            goto too_long_error;
2931 +        }
2932 +
2933 +      page_unlock (upage);
2934 +    }
2935 +
2936 + too_long_error:
2937 +  page_unlock (upage);
2938 + lock_error:
2939 +  palloc_free_page (ks);
2940    thread_exit ();
2941  }
2942
2943 +/* Halt system call. */
2944 +static int
2945 +sys_halt (void)
2946 +{
2947 +  power_off ();
2948 +}
2949
2950 +/* Exit system call. */
2951 +static int
2952 +sys_exit (int exit_code) 
2953 +{
2954 +  thread_current ()->exit_code = exit_code;
2955 +  thread_exit ();
2956 +  NOT_REACHED ();
2957 +}
2958
2959 +/* Exec system call. */
2960 +static int
2961 +sys_exec (const char *ufile) 
2962 +{
2963 +  tid_t tid;
2964 +  char *kfile = copy_in_string (ufile);
2965
2966 +  tid = process_execute (kfile);
2967
2968 +  palloc_free_page (kfile);
2969
2970 +  return tid;
2971 +}
2972
2973 +/* Wait system call. */
2974 +static int
2975 +sys_wait (tid_t child) 
2976 +{
2977 +  return process_wait (child);
2978 +}
2979
2980 +/* Create system call. */
2981 +static int
2982 +sys_create (const char *ufile, unsigned initial_size) 
2983 +{
2984 +  char *kfile = copy_in_string (ufile);
2985 +  bool ok = filesys_create (kfile, initial_size, FILE_INODE);
2986 +  palloc_free_page (kfile);
2987
2988 +  return ok;
2989 +}
2990
2991 +/* Remove system call. */
2992 +static int
2993 +sys_remove (const char *ufile) 
2994 +{
2995 +  char *kfile = copy_in_string (ufile);
2996 +  bool ok = filesys_remove (kfile);
2997 +  palloc_free_page (kfile);
2998
2999 +  return ok;
3000 +}
3001 +\f
3002 +/* A file descriptor, for binding a file handle to a file. */
3003 +struct file_descriptor
3004 +  {
3005 +    struct list_elem elem;      /* List element. */
3006 +    struct file *file;          /* File. */
3007 +    struct dir *dir;            /* Directory. */
3008 +    int handle;                 /* File handle. */
3009 +  };
3010
3011 +/* Open system call. */
3012 +static int
3013 +sys_open (const char *ufile) 
3014 +{
3015 +  char *kfile = copy_in_string (ufile);
3016 +  struct file_descriptor *fd;
3017 +  int handle = -1;
3018
3019 +  fd = calloc (1, sizeof *fd);
3020 +  if (fd != NULL)
3021 +    {
3022 +      struct inode *inode = filesys_open (kfile);
3023 +      if (inode != NULL)
3024 +        {
3025 +          if (inode_get_type (inode) == FILE_INODE)
3026 +            fd->file = file_open (inode);
3027 +          else
3028 +            fd->dir = dir_open (inode);
3029 +          if (fd->file != NULL || fd->dir != NULL)
3030 +            {
3031 +              struct thread *cur = thread_current ();
3032 +              handle = fd->handle = cur->next_handle++;
3033 +              list_push_front (&cur->fds, &fd->elem);
3034 +            }
3035 +          else 
3036 +            {
3037 +              free (fd);
3038 +              inode_close (inode);
3039 +            }
3040 +        }
3041 +    }
3042 +  
3043 +  palloc_free_page (kfile);
3044 +  return handle;
3045 +}
3046
3047 +/* Returns the file descriptor associated with the given handle.
3048 +   Terminates the process if HANDLE is not associated with an
3049 +   open file. */
3050 +static struct file_descriptor *
3051 +lookup_fd (int handle) 
3052 +{
3053 +  struct thread *cur = thread_current ();
3054 +  struct list_elem *e;
3055 +   
3056 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
3057 +       e = list_next (e))
3058 +    {
3059 +      struct file_descriptor *fd;
3060 +      fd = list_entry (e, struct file_descriptor, elem);
3061 +      if (fd->handle == handle)
3062 +        return fd;
3063 +    }
3064
3065 +  thread_exit ();
3066 +}
3067
3068 +/* Returns the file descriptor associated with the given handle.
3069 +   Terminates the process if HANDLE is not associated with an
3070 +   open ordinary file. */
3071 +static struct file_descriptor *
3072 +lookup_file_fd (int handle) 
3073 +{
3074 +  struct file_descriptor *fd = lookup_fd (handle);
3075 +  if (fd->file == NULL)
3076 +    thread_exit ();
3077 +  return fd;
3078 +}
3079
3080 +/* Returns the file descriptor associated with the given handle.
3081 +   Terminates the process if HANDLE is not associated with an
3082 +   open directory. */
3083 +static struct file_descriptor *
3084 +lookup_dir_fd (int handle) 
3085 +{
3086 +  struct file_descriptor *fd = lookup_fd (handle);
3087 +  if (fd->dir == NULL)
3088 +    thread_exit ();
3089 +  return fd;
3090 +}
3091 +
3092 +/* Filesize system call. */
3093 +static int
3094 +sys_filesize (int handle) 
3095 +{
3096 +  struct file_descriptor *fd = lookup_file_fd (handle);
3097 +  int size;
3098
3099 +  size = file_length (fd->file);
3100
3101 +  return size;
3102 +}
3103
3104 +/* Read system call. */
3105 +static int
3106 +sys_read (int handle, void *udst_, unsigned size) 
3107 +{
3108 +  uint8_t *udst = udst_;
3109 +  struct file_descriptor *fd;
3110 +  int bytes_read = 0;
3111 +
3112 +  /* Look up file descriptor. */
3113 +  if (handle != STDIN_FILENO)
3114 +    fd = lookup_file_fd (handle);
3115 +
3116 +  while (size > 0) 
3117 +    {
3118 +      /* How much to read into this page? */
3119 +      size_t page_left = PGSIZE - pg_ofs (udst);
3120 +      size_t read_amt = size < page_left ? size : page_left;
3121 +      off_t retval;
3122 +
3123 +      /* Check that touching this page is okay. */
3124 +      if (!page_lock (udst, true)) 
3125 +        thread_exit ();
3126 +
3127 +      /* Read from file into page. */
3128 +      if (handle != STDIN_FILENO) 
3129 +        {
3130 +          retval = file_read (fd->file, udst, read_amt);
3131 +          if (retval < 0)
3132 +            {
3133 +              if (bytes_read == 0)
3134 +                bytes_read = -1; 
3135 +              break;
3136 +            }
3137 +          bytes_read += retval; 
3138 +        }
3139 +      else 
3140 +        {
3141 +          size_t i;
3142 +          
3143 +          for (i = 0; i < read_amt; i++) 
3144 +            udst[i] = kbd_getc ();
3145 +          bytes_read = read_amt;
3146 +        }
3147 +
3148 +      /* Release page. */
3149 +      page_unlock (udst);
3150 +
3151 +      /* If it was a short read we're done. */
3152 +      if (retval != (off_t) read_amt)
3153 +        break;
3154 +
3155 +      /* Advance. */
3156 +      udst += retval;
3157 +      size -= retval;
3158 +    }
3159 +   
3160 +  return bytes_read;
3161 +}
3162
3163 +/* Write system call. */
3164 +static int
3165 +sys_write (int handle, void *usrc_, unsigned size) 
3166 +{
3167 +  uint8_t *usrc = usrc_;
3168 +  struct file_descriptor *fd = NULL;
3169 +  int bytes_written = 0;
3170 +
3171 +  /* Lookup up file descriptor. */
3172 +  if (handle != STDOUT_FILENO)
3173 +    fd = lookup_file_fd (handle);
3174 +
3175 +  while (size > 0) 
3176 +    {
3177 +      /* How much bytes to write to this page? */
3178 +      size_t page_left = PGSIZE - pg_ofs (usrc);
3179 +      size_t write_amt = size < page_left ? size : page_left;
3180 +      off_t retval;
3181 +
3182 +      /* Check that we can touch this user page. */
3183 +      if (!page_lock (usrc, false)) 
3184 +        thread_exit ();
3185 +
3186 +      /* Do the write. */
3187 +      if (handle == STDOUT_FILENO)
3188 +        {
3189 +          putbuf ((char *) usrc, write_amt);
3190 +          retval = write_amt;
3191 +        }
3192 +      else
3193 +        retval = file_write (fd->file, usrc, write_amt);
3194 +
3195 +      /* Release user page. */
3196 +      page_unlock (usrc);
3197 +
3198 +      /* Handle return value. */
3199 +      if (retval < 0) 
3200 +        {
3201 +          if (bytes_written == 0)
3202 +            bytes_written = -1;
3203 +          break;
3204 +        }
3205 +      bytes_written += retval;
3206 +
3207 +      /* If it was a short write we're done. */
3208 +      if (retval != (off_t) write_amt)
3209 +        break;
3210 +
3211 +      /* Advance. */
3212 +      usrc += retval;
3213 +      size -= retval;
3214 +    }
3215
3216 +  return bytes_written;
3217 +}
3218
3219 +/* Seek system call. */
3220 +static int
3221 +sys_seek (int handle, unsigned position) 
3222 +{
3223 +  if ((off_t) position >= 0)
3224 +    file_seek (lookup_file_fd (handle)->file, position);
3225 +  return 0;
3226 +}
3227
3228 +/* Tell system call. */
3229 +static int
3230 +sys_tell (int handle) 
3231 +{
3232 +  return file_tell (lookup_file_fd (handle)->file);
3233 +}
3234
3235 +/* Close system call. */
3236 +static int
3237 +sys_close (int handle) 
3238 +{
3239 +  struct file_descriptor *fd = lookup_fd (handle);
3240 +  file_close (fd->file);
3241 +  dir_close (fd->dir);
3242 +  list_remove (&fd->elem);
3243 +  free (fd);
3244 +  return 0;
3245 +}
3246 +\f
3247 +/* Binds a mapping id to a region of memory and a file. */
3248 +struct mapping
3249 +  {
3250 +    struct list_elem elem;      /* List element. */
3251 +    int handle;                 /* Mapping id. */
3252 +    struct file *file;          /* File. */
3253 +    uint8_t *base;              /* Start of memory mapping. */
3254 +    size_t page_cnt;            /* Number of pages mapped. */
3255 +  };
3256 +
3257 +/* Returns the file descriptor associated with the given handle.
3258 +   Terminates the process if HANDLE is not associated with a
3259 +   memory mapping. */
3260 +static struct mapping *
3261 +lookup_mapping (int handle) 
3262 +{
3263 +  struct thread *cur = thread_current ();
3264 +  struct list_elem *e;
3265 +   
3266 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
3267 +       e = list_next (e))
3268 +    {
3269 +      struct mapping *m = list_entry (e, struct mapping, elem);
3270 +      if (m->handle == handle)
3271 +        return m;
3272 +    }
3273
3274 +  thread_exit ();
3275 +}
3276 +
3277 +/* Remove mapping M from the virtual address space,
3278 +   writing back any pages that have changed. */
3279 +static void
3280 +unmap (struct mapping *m) 
3281 +{
3282 +  list_remove (&m->elem);
3283 +  while (m->page_cnt-- > 0) 
3284 +    {
3285 +      page_deallocate (m->base);
3286 +      m->base += PGSIZE;
3287 +    }
3288 +  file_close (m->file);
3289 +  free (m);
3290 +}
3291
3292 +/* Mmap system call. */
3293 +static int
3294 +sys_mmap (int handle, void *addr)
3295 +{
3296 +  struct file_descriptor *fd = lookup_file_fd (handle);
3297 +  struct mapping *m = malloc (sizeof *m);
3298 +  size_t offset;
3299 +  off_t length;
3300 +
3301 +  if (m == NULL || addr == NULL || pg_ofs (addr) != 0)
3302 +    return -1;
3303 +
3304 +  m->handle = thread_current ()->next_handle++;
3305 +  m->file = file_reopen (fd->file);
3306 +  if (m->file == NULL) 
3307 +    {
3308 +      free (m);
3309 +      return -1;
3310 +    }
3311 +  m->base = addr;
3312 +  m->page_cnt = 0;
3313 +  list_push_front (&thread_current ()->mappings, &m->elem);
3314 +
3315 +  offset = 0;
3316 +  length = file_length (m->file);
3317 +  while (length > 0)
3318 +    {
3319 +      struct page *p = page_allocate ((uint8_t *) addr + offset, false);
3320 +      if (p == NULL)
3321 +        {
3322 +          unmap (m);
3323 +          return -1;
3324 +        }
3325 +      p->private = false;
3326 +      p->file = m->file;
3327 +      p->file_offset = offset;
3328 +      p->file_bytes = length >= PGSIZE ? PGSIZE : length;
3329 +      offset += p->file_bytes;
3330 +      length -= p->file_bytes;
3331 +      m->page_cnt++;
3332 +    }
3333 +  
3334 +  return m->handle;
3335 +}
3336 +
3337 +/* Munmap system call. */
3338 +static int
3339 +sys_munmap (int mapping) 
3340 +{
3341 +  unmap (lookup_mapping (mapping));
3342 +  return 0;
3343 +}
3344 +
3345 +/* Chdir system call. */
3346 +static int
3347 +sys_chdir (const char *udir) 
3348 +{
3349 +  char *kdir = copy_in_string (udir);
3350 +  bool ok = filesys_chdir (kdir);
3351 +  palloc_free_page (kdir);
3352 +  return ok;
3353 +}
3354 +
3355 +/* Mkdir system call. */
3356 +static int
3357 +sys_mkdir (const char *udir)
3358 +{
3359 +  char *kdir = copy_in_string (udir);
3360 +  bool ok = filesys_create (kdir, 0, DIR_INODE);
3361 +  palloc_free_page (kdir);
3362
3363 +  return ok;
3364 +}
3365 +
3366 +/* Readdir system call. */
3367 +static int
3368 +sys_readdir (int handle, char *uname)
3369 +{
3370 +  struct file_descriptor *fd = lookup_dir_fd (handle);
3371 +  char name[NAME_MAX + 1];
3372 +  bool ok = dir_readdir (fd->dir, name);
3373 +  if (ok)
3374 +    copy_out (uname, name, strlen (name) + 1);
3375 +  return ok;
3376 +}
3377 +
3378 +/* Isdir system call. */
3379 +static int
3380 +sys_isdir (int handle)
3381 +{
3382 +  struct file_descriptor *fd = lookup_fd (handle);
3383 +  return fd->dir != NULL;
3384 +}
3385 +
3386 +/* Inumber system call. */
3387 +static int
3388 +sys_inumber (int handle)
3389 +{
3390 +  struct file_descriptor *fd = lookup_fd (handle);
3391 +  struct inode *inode = (fd->file 
3392 +                         ? file_get_inode (fd->file)
3393 +                         : dir_get_inode (fd->dir));
3394 +  return inode_get_inumber (inode);
3395 +}
3396 +\f 
3397 +/* On thread exit, close all open files and unmap all mappings. */
3398 +void
3399 +syscall_exit (void) 
3400 +{
3401 +  struct thread *cur = thread_current ();
3402 +  struct list_elem *e, *next;
3403 +   
3404 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
3405 +    {
3406 +      struct file_descriptor *fd = list_entry (e, struct file_descriptor, elem);
3407 +      next = list_next (e);
3408 +      file_close (fd->file);
3409 +      dir_close (fd->dir);
3410 +      free (fd);
3411 +    }
3412 +   
3413 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
3414 +       e = next)
3415 +    {
3416 +      struct mapping *m = list_entry (e, struct mapping, elem);
3417 +      next = list_next (e);
3418 +      unmap (m);
3419 +    }
3420 +
3421 +  dir_close (cur->wd);
3422 +}
3423 Index: src/userprog/syscall.h
3424 diff -u src/userprog/syscall.h~ src/userprog/syscall.h
3425 --- src/userprog/syscall.h~
3426 +++ src/userprog/syscall.h
3427 @@ -2,5 +2,6 @@
3428  #define USERPROG_SYSCALL_H
3429  
3430  void syscall_init (void);
3431 +void syscall_exit (void);
3432  
3433  #endif /* userprog/syscall.h */
3434 Index: src/vm/frame.c
3435 diff -u src/vm/frame.c~ src/vm/frame.c
3436 --- src/vm/frame.c~
3437 +++ src/vm/frame.c
3438 @@ -0,0 +1,161 @@
3439 +#include "vm/frame.h"
3440 +#include <stdio.h>
3441 +#include "vm/page.h"
3442 +#include "devices/timer.h"
3443 +#include "threads/init.h"
3444 +#include "threads/malloc.h"
3445 +#include "threads/palloc.h"
3446 +#include "threads/synch.h"
3447 +#include "threads/vaddr.h"
3448 +
3449 +static struct frame *frames;
3450 +static size_t frame_cnt;
3451 +
3452 +static struct lock scan_lock;
3453 +static size_t hand;
3454 +
3455 +/* Initialize the frame manager. */
3456 +void
3457 +frame_init (void) 
3458 +{
3459 +  void *base;
3460 +
3461 +  lock_init (&scan_lock);
3462 +  
3463 +  frames = malloc (sizeof *frames * ram_pages);
3464 +  if (frames == NULL)
3465 +    PANIC ("out of memory allocating page frames");
3466 +
3467 +  while ((base = palloc_get_page (PAL_USER)) != NULL) 
3468 +    {
3469 +      struct frame *f = &frames[frame_cnt++];
3470 +      lock_init (&f->lock);
3471 +      f->base = base;
3472 +      f->page = NULL;
3473 +    }
3474 +}
3475 +
3476 +/* Tries to allocate and lock a frame for PAGE.
3477 +   Returns the frame if successful, false on failure. */
3478 +static struct frame *
3479 +try_frame_alloc_and_lock (struct page *page) 
3480 +{
3481 +  size_t i;
3482 +
3483 +  lock_acquire (&scan_lock);
3484 +
3485 +  /* Find a free frame. */
3486 +  for (i = 0; i < frame_cnt; i++)
3487 +    {
3488 +      struct frame *f = &frames[i];
3489 +      if (!lock_try_acquire (&f->lock))
3490 +        continue;
3491 +      if (f->page == NULL) 
3492 +        {
3493 +          f->page = page;
3494 +          lock_release (&scan_lock);
3495 +          return f;
3496 +        } 
3497 +      lock_release (&f->lock);
3498 +    }
3499 +
3500 +  /* No free frame.  Find a frame to evict. */
3501 +  for (i = 0; i < frame_cnt * 2; i++) 
3502 +    {
3503 +      /* Get a frame. */
3504 +      struct frame *f = &frames[hand];
3505 +      if (++hand >= frame_cnt)
3506 +        hand = 0;
3507 +
3508 +      if (!lock_try_acquire (&f->lock))
3509 +        continue;
3510 +
3511 +      if (f->page == NULL) 
3512 +        {
3513 +          f->page = page;
3514 +          lock_release (&scan_lock);
3515 +          return f;
3516 +        } 
3517 +
3518 +      if (page_accessed_recently (f->page)) 
3519 +        {
3520 +          lock_release (&f->lock);
3521 +          continue;
3522 +        }
3523 +          
3524 +      lock_release (&scan_lock);
3525 +      
3526 +      /* Evict this frame. */
3527 +      if (!page_out (f->page))
3528 +        {
3529 +          lock_release (&f->lock);
3530 +          return NULL;
3531 +        }
3532 +
3533 +      f->page = page;
3534 +      return f;
3535 +    }
3536 +
3537 +  lock_release (&scan_lock);
3538 +  return NULL;
3539 +}
3540 +
3541 +/* Tries really hard to allocate and lock a frame for PAGE.
3542 +   Returns the frame if successful, false on failure. */
3543 +struct frame *
3544 +frame_alloc_and_lock (struct page *page) 
3545 +{
3546 +  size_t try;
3547 +
3548 +  for (try = 0; try < 3; try++) 
3549 +    {
3550 +      struct frame *f = try_frame_alloc_and_lock (page);
3551 +      if (f != NULL) 
3552 +        {
3553 +          ASSERT (lock_held_by_current_thread (&f->lock));
3554 +          return f; 
3555 +        }
3556 +      timer_msleep (1000);
3557 +    }
3558 +
3559 +  return NULL;
3560 +}
3561 +
3562 +/* Locks P's frame into memory, if it has one.
3563 +   Upon return, p->frame will not change until P is unlocked. */
3564 +void
3565 +frame_lock (struct page *p) 
3566 +{
3567 +  /* A frame can be asynchronously removed, but never inserted. */
3568 +  struct frame *f = p->frame;
3569 +  if (f != NULL) 
3570 +    {
3571 +      lock_acquire (&f->lock);
3572 +      if (f != p->frame)
3573 +        {
3574 +          lock_release (&f->lock);
3575 +          ASSERT (p->frame == NULL); 
3576 +        } 
3577 +    }
3578 +}
3579 +
3580 +/* Releases frame F for use by another page.
3581 +   F must be locked for use by the current process.
3582 +   Any data in F is lost. */
3583 +void
3584 +frame_free (struct frame *f)
3585 +{
3586 +  ASSERT (lock_held_by_current_thread (&f->lock));
3587 +          
3588 +  f->page = NULL;
3589 +  lock_release (&f->lock);
3590 +}
3591 +
3592 +/* Unlocks frame F, allowing it to be evicted.
3593 +   F must be locked for use by the current process. */
3594 +void
3595 +frame_unlock (struct frame *f) 
3596 +{
3597 +  ASSERT (lock_held_by_current_thread (&f->lock));
3598 +  lock_release (&f->lock);
3599 +}
3600 Index: src/vm/frame.h
3601 diff -u src/vm/frame.h~ src/vm/frame.h
3602 --- src/vm/frame.h~
3603 +++ src/vm/frame.h
3604 @@ -0,0 +1,23 @@
3605 +#ifndef VM_FRAME_H
3606 +#define VM_FRAME_H
3607 +
3608 +#include <stdbool.h>
3609 +#include "threads/synch.h"
3610 +
3611 +/* A physical frame. */
3612 +struct frame 
3613 +  {
3614 +    struct lock lock;           /* Prevent simultaneous access. */
3615 +    void *base;                 /* Kernel virtual base address. */
3616 +    struct page *page;          /* Mapped process page, if any. */
3617 +  };
3618 +
3619 +void frame_init (void);
3620 +
3621 +struct frame *frame_alloc_and_lock (struct page *);
3622 +void frame_lock (struct page *);
3623 +
3624 +void frame_free (struct frame *);
3625 +void frame_unlock (struct frame *);
3626 +
3627 +#endif /* vm/frame.h */
3628 Index: src/vm/page.c
3629 diff -u src/vm/page.c~ src/vm/page.c
3630 --- src/vm/page.c~
3631 +++ src/vm/page.c
3632 @@ -0,0 +1,294 @@
3633 +#include "vm/page.h"
3634 +#include <stdio.h>
3635 +#include <string.h>
3636 +#include "vm/frame.h"
3637 +#include "vm/swap.h"
3638 +#include "filesys/file.h"
3639 +#include "threads/malloc.h"
3640 +#include "threads/thread.h"
3641 +#include "userprog/pagedir.h"
3642 +#include "threads/vaddr.h"
3643 +
3644 +/* Maximum size of process stack, in bytes. */
3645 +#define STACK_MAX (1024 * 1024)
3646 +
3647 +/* Destroys a page, which must be in the current process's
3648 +   page table.  Used as a callback for hash_destroy(). */
3649 +static void
3650 +destroy_page (struct hash_elem *p_, void *aux UNUSED)
3651 +{
3652 +  struct page *p = hash_entry (p_, struct page, hash_elem);
3653 +  frame_lock (p);
3654 +  if (p->frame)
3655 +    frame_free (p->frame);
3656 +  free (p);
3657 +}
3658 +
3659 +
3660 +/* Destroys the current process's page table. */
3661 +void
3662 +page_exit (void) 
3663 +{
3664 +  struct hash *h = thread_current ()->pages;
3665 +  if (h != NULL)
3666 +    hash_destroy (h, destroy_page);
3667 +}
3668 +
3669 +/* Returns the page containing the given virtual ADDRESS,
3670 +   or a null pointer if no such page exists.
3671 +   Allocates stack pages as necessary. */
3672 +static struct page *
3673 +page_for_addr (const void *address) 
3674 +{
3675 +  if (address < PHYS_BASE) 
3676 +    {
3677 +      struct page p;
3678 +      struct hash_elem *e;
3679 +
3680 +      /* Find existing page. */
3681 +      p.addr = (void *) pg_round_down (address);
3682 +      e = hash_find (thread_current ()->pages, &p.hash_elem);
3683 +      if (e != NULL)
3684 +        return hash_entry (e, struct page, hash_elem);
3685 +
3686 +      /* No page.  Expand stack? */
3687 +      if (address >= PHYS_BASE - STACK_MAX
3688 +          && address >= thread_current ()->user_esp - 32)
3689 +        return page_allocate ((void *) address, false);
3690 +    }
3691 +  return NULL;
3692 +}
3693 +
3694 +/* Locks a frame for page P and pages it in.
3695 +   Returns true if successful, false on failure. */
3696 +static bool
3697 +do_page_in (struct page *p)
3698 +{
3699 +  /* Get a frame for the page. */
3700 +  p->frame = frame_alloc_and_lock (p);
3701 +  if (p->frame == NULL)
3702 +    return false;
3703 +
3704 +  /* Copy data into the frame. */
3705 +  if (p->sector != (disk_sector_t) -1) 
3706 +    {
3707 +      /* Get data from swap. */
3708 +      swap_in (p); 
3709 +    }
3710 +  else if (p->file != NULL) 
3711 +    {
3712 +      /* Get data from file. */
3713 +      off_t read_bytes = file_read_at (p->file, p->frame->base,
3714 +                                        p->file_bytes, p->file_offset);
3715 +      off_t zero_bytes = PGSIZE - read_bytes;
3716 +      memset (p->frame->base + read_bytes, 0, zero_bytes);
3717 +      if (read_bytes != p->file_bytes)
3718 +        printf ("bytes read (%"PROTd") != bytes requested (%"PROTd")\n",
3719 +                read_bytes, p->file_bytes);
3720 +    }
3721 +  else 
3722 +    {
3723 +      /* Provide all-zero page. */
3724 +      memset (p->frame->base, 0, PGSIZE);
3725 +    }
3726 +
3727 +  return true;
3728 +}
3729 +
3730 +/* Faults in the page containing FAULT_ADDR.
3731 +   Returns true if successful, false on failure. */
3732 +bool
3733 +page_in (void *fault_addr) 
3734 +{
3735 +  struct page *p;
3736 +  bool success;
3737 +
3738 +  /* Can't handle page faults without a hash table. */
3739 +  if (thread_current ()->pages == NULL) 
3740 +    return false;
3741 +
3742 +  p = page_for_addr (fault_addr);
3743 +  if (p == NULL) 
3744 +    return false; 
3745 +
3746 +  frame_lock (p);
3747 +  if (p->frame == NULL)
3748 +    {
3749 +      if (!do_page_in (p))
3750 +        return false;
3751 +    }
3752 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
3753 +    
3754 +  /* Install frame into page table. */
3755 +  success = pagedir_set_page (thread_current ()->pagedir, p->addr,
3756 +                              p->frame->base, !p->read_only);
3757 +
3758 +  /* Release frame. */
3759 +  frame_unlock (p->frame);
3760 +
3761 +  return success;
3762 +}
3763 +
3764 +/* Evicts page P.
3765 +   P must have a locked frame.
3766 +   Return true if successful, false on failure. */
3767 +bool
3768 +page_out (struct page *p) 
3769 +{
3770 +  bool dirty;
3771 +  bool ok;
3772 +
3773 +  ASSERT (p->frame != NULL);
3774 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
3775 +
3776 +  /* Mark page not present in page table, forcing accesses by the
3777 +     process to fault.  This must happen before checking the
3778 +     dirty bit, to prevent a race with the process dirtying the
3779 +     page. */
3780 +  pagedir_clear_page (p->thread->pagedir, p->addr);
3781 +
3782 +  /* Has the frame been modified? */
3783 +  dirty = pagedir_is_dirty (p->thread->pagedir, p->addr);
3784 +
3785 +  /* Write frame contents to disk if necessary. */
3786 +  if (p->file != NULL) 
3787 +    {
3788 +      if (dirty) 
3789 +        {
3790 +          if (p->private)
3791 +            ok = swap_out (p);
3792 +          else 
3793 +            ok = file_write_at (p->file, p->frame->base, p->file_bytes,
3794 +                                p->file_offset) == p->file_bytes;
3795 +        }
3796 +      else
3797 +        ok = true;
3798 +    }
3799 +  else
3800 +    ok = swap_out (p);
3801 +  if (ok) 
3802 +    {
3803 +      //memset (p->frame->base, 0xcc, PGSIZE);
3804 +      p->frame = NULL; 
3805 +    }
3806 +  return ok;
3807 +}
3808 +
3809 +/* Returns true if page P's data has been accessed recently,
3810 +   false otherwise.
3811 +   P must have a frame locked into memory. */
3812 +bool
3813 +page_accessed_recently (struct page *p) 
3814 +{
3815 +  bool was_accessed;
3816 +
3817 +  ASSERT (p->frame != NULL);
3818 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
3819 +
3820 +  was_accessed = pagedir_is_accessed (p->thread->pagedir, p->addr);
3821 +  if (was_accessed)
3822 +    pagedir_set_accessed (p->thread->pagedir, p->addr, false);
3823 +  return was_accessed;
3824 +}
3825 +
3826 +/* Adds a mapping for user virtual address VADDR to the page hash
3827 +   table.  Fails if VADDR is already mapped or if memory
3828 +   allocation fails. */
3829 +struct page *
3830 +page_allocate (void *vaddr, bool read_only)
3831 +{
3832 +  struct thread *t = thread_current ();
3833 +  struct page *p = malloc (sizeof *p);
3834 +  if (p != NULL) 
3835 +    {
3836 +      p->addr = pg_round_down (vaddr);
3837 +
3838 +      p->read_only = read_only;
3839 +      p->private = !read_only;
3840 +
3841 +      p->frame = NULL;
3842 +
3843 +      p->sector = (disk_sector_t) -1;
3844 +
3845 +      p->file = NULL;
3846 +      p->file_offset = 0;
3847 +      p->file_bytes = 0;
3848 +
3849 +      p->thread = thread_current ();
3850 +
3851 +      if (hash_insert (t->pages, &p->hash_elem) != NULL) 
3852 +        {
3853 +          /* Already mapped. */
3854 +          free (p);
3855 +          p = NULL;
3856 +        }
3857 +    }
3858 +  return p;
3859 +}
3860 +
3861 +/* Evicts the page containing address VADDR
3862 +   and removes it from the page table. */
3863 +void
3864 +page_deallocate (void *vaddr) 
3865 +{
3866 +  struct page *p = page_for_addr (vaddr);
3867 +  ASSERT (p != NULL);
3868 +  frame_lock (p);
3869 +  if (p->frame)
3870 +    {
3871 +      struct frame *f = p->frame;
3872 +      if (p->file && !p->private) 
3873 +        page_out (p); 
3874 +      frame_free (f);
3875 +    }
3876 +  hash_delete (thread_current ()->pages, &p->hash_elem);
3877 +  free (p);
3878 +}
3879 +
3880 +/* Returns a hash value for the page that E refers to. */
3881 +unsigned
3882 +page_hash (const struct hash_elem *e, void *aux UNUSED) 
3883 +{
3884 +  const struct page *p = hash_entry (e, struct page, hash_elem);
3885 +  return ((uintptr_t) p->addr) >> PGBITS;
3886 +}
3887 +
3888 +/* Returns true if page A precedes page B. */
3889 +bool
3890 +page_less (const struct hash_elem *a_, const struct hash_elem *b_,
3891 +           void *aux UNUSED) 
3892 +{
3893 +  const struct page *a = hash_entry (a_, struct page, hash_elem);
3894 +  const struct page *b = hash_entry (b_, struct page, hash_elem);
3895 +  
3896 +  return a->addr < b->addr;
3897 +}
3898 +
3899 +/* Tries to lock the page containing ADDR into physical memory.
3900 +   If WILL_WRITE is true, the page must be writeable;
3901 +   otherwise it may be read-only.
3902 +   Returns true if successful, false on failure. */
3903 +bool
3904 +page_lock (const void *addr, bool will_write) 
3905 +{
3906 +  struct page *p = page_for_addr (addr);
3907 +  if (p == NULL || (p->read_only && will_write))
3908 +    return false;
3909 +  
3910 +  frame_lock (p);
3911 +  if (p->frame == NULL)
3912 +    return (do_page_in (p)
3913 +            && pagedir_set_page (thread_current ()->pagedir, p->addr,
3914 +                                 p->frame->base, !p->read_only)); 
3915 +  else
3916 +    return true;
3917 +}
3918 +
3919 +/* Unlocks a page locked with page_lock(). */
3920 +void
3921 +page_unlock (const void *addr) 
3922 +{
3923 +  struct page *p = page_for_addr (addr);
3924 +  ASSERT (p != NULL);
3925 +  frame_unlock (p->frame);
3926 +}
3927 Index: src/vm/page.h
3928 diff -u src/vm/page.h~ src/vm/page.h
3929 --- src/vm/page.h~
3930 +++ src/vm/page.h
3931 @@ -0,0 +1,50 @@
3932 +#ifndef VM_PAGE_H
3933 +#define VM_PAGE_H
3934 +
3935 +#include <hash.h>
3936 +#include "devices/disk.h"
3937 +#include "filesys/off_t.h"
3938 +#include "threads/synch.h"
3939 +
3940 +/* Virtual page. */
3941 +struct page 
3942 +  {
3943 +    /* Immutable members. */
3944 +    void *addr;                 /* User virtual address. */
3945 +    bool read_only;             /* Read-only page? */
3946 +    struct thread *thread;      /* Owning thread. */
3947 +
3948 +    /* Accessed only in owning process context. */
3949 +    struct hash_elem hash_elem; /* struct thread `pages' hash element. */
3950 +
3951 +    /* Set only in owning process context with frame->frame_lock held.
3952 +       Cleared only with scan_lock and frame->frame_lock held. */
3953 +    struct frame *frame;        /* Page frame. */
3954 +
3955 +    /* Swap information, protected by frame->frame_lock. */
3956 +    disk_sector_t sector;       /* Starting sector of swap area, or -1. */
3957 +    
3958 +    /* Memory-mapped file information, protected by frame->frame_lock. */
3959 +    bool private;               /* False to write back to file,
3960 +                                   true to write back to swap. */
3961 +    struct file *file;          /* File. */
3962 +    off_t file_offset;          /* Offset in file. */
3963 +    off_t file_bytes;           /* Bytes to read/write, 1...PGSIZE. */
3964 +  };
3965 +
3966 +void page_exit (void);
3967 +
3968 +struct page *page_allocate (void *, bool read_only);
3969 +void page_deallocate (void *vaddr);
3970 +
3971 +bool page_in (void *fault_addr);
3972 +bool page_out (struct page *);
3973 +bool page_accessed_recently (struct page *);
3974 +
3975 +bool page_lock (const void *, bool will_write);
3976 +void page_unlock (const void *);
3977 +
3978 +hash_hash_func page_hash;
3979 +hash_less_func page_less;
3980 +
3981 +#endif /* vm/page.h */
3982 Index: src/vm/swap.c
3983 diff -u src/vm/swap.c~ src/vm/swap.c
3984 --- src/vm/swap.c~
3985 +++ src/vm/swap.c
3986 @@ -0,0 +1,85 @@
3987 +#include "vm/swap.h"
3988 +#include <bitmap.h>
3989 +#include <debug.h>
3990 +#include <stdio.h>
3991 +#include "vm/frame.h"
3992 +#include "vm/page.h"
3993 +#include "devices/disk.h"
3994 +#include "threads/synch.h"
3995 +#include "threads/vaddr.h"
3996 +
3997 +/* The swap disk. */
3998 +static struct disk *swap_disk;
3999 +
4000 +/* Used swap pages. */
4001 +static struct bitmap *swap_bitmap;
4002 +
4003 +/* Protects swap_bitmap. */
4004 +static struct lock swap_lock;
4005 +
4006 +/* Number of sectors per page. */
4007 +#define PAGE_SECTORS (PGSIZE / DISK_SECTOR_SIZE)
4008 +
4009 +/* Sets up swap. */
4010 +void
4011 +swap_init (void) 
4012 +{
4013 +  swap_disk = disk_get (1, 1);
4014 +  if (swap_disk == NULL) 
4015 +    {
4016 +      printf ("no swap disk--swap disabled\n");
4017 +      swap_bitmap = bitmap_create (0);
4018 +    }
4019 +  else
4020 +    swap_bitmap = bitmap_create (disk_size (swap_disk) / PAGE_SECTORS);
4021 +  if (swap_bitmap == NULL)
4022 +    PANIC ("couldn't create swap bitmap");
4023 +  lock_init (&swap_lock);
4024 +}
4025 +
4026 +/* Swaps in page P, which must have a locked frame
4027 +   (and be swapped out). */
4028 +void
4029 +swap_in (struct page *p) 
4030 +{
4031 +  size_t i;
4032 +  
4033 +  ASSERT (p->frame != NULL);
4034 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
4035 +  ASSERT (p->sector != (disk_sector_t) -1);
4036 +
4037 +  for (i = 0; i < PAGE_SECTORS; i++)
4038 +    disk_read (swap_disk, p->sector + i,
4039 +               p->frame->base + i * DISK_SECTOR_SIZE);
4040 +  bitmap_reset (swap_bitmap, p->sector / PAGE_SECTORS);
4041 +  p->sector = (disk_sector_t) -1;
4042 +}
4043 +
4044 +/* Swaps out page P, which must have a locked frame. */
4045 +bool
4046 +swap_out (struct page *p) 
4047 +{
4048 +  size_t slot;
4049 +  size_t i;
4050 +
4051 +  ASSERT (p->frame != NULL);
4052 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
4053 +
4054 +  lock_acquire (&swap_lock);
4055 +  slot = bitmap_scan_and_flip (swap_bitmap, 0, 1, false);
4056 +  lock_release (&swap_lock);
4057 +  if (slot == BITMAP_ERROR) 
4058 +    return false; 
4059 +
4060 +  p->sector = slot * PAGE_SECTORS;
4061 +  for (i = 0; i < PAGE_SECTORS; i++)
4062 +    disk_write (swap_disk, p->sector + i,
4063 +                p->frame->base + i * DISK_SECTOR_SIZE);
4064 +  
4065 +  p->private = false;
4066 +  p->file = NULL;
4067 +  p->file_offset = 0;
4068 +  p->file_bytes = 0;
4069 +
4070 +  return true;
4071 +}
4072 Index: src/vm/swap.h
4073 diff -u src/vm/swap.h~ src/vm/swap.h
4074 --- src/vm/swap.h~
4075 +++ src/vm/swap.h
4076 @@ -0,0 +1,11 @@
4077 +#ifndef VM_SWAP_H
4078 +#define VM_SWAP_H 1
4079 +
4080 +#include <stdbool.h>
4081 +
4082 +struct page;
4083 +void swap_init (void);
4084 +void swap_in (struct page *);
4085 +bool swap_out (struct page *);
4086 +
4087 +#endif /* vm/swap.h */