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