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