++/* Tries to lock the page containing ADDR into physical memory.
++ If WILL_WRITE is true, the page must be writeable;
++ otherwise it may be read-only.
++ Returns true if successful, false on failure. */
++bool
++page_lock (const void *addr, bool will_write)
++{
++ struct page *p = page_for_addr (addr);
++ if (p == NULL || (p->read_only && will_write))
++ return false;
++
++ frame_lock (p);
++ if (p->frame == NULL)
++ return (do_page_in (p)
++ && pagedir_set_page (thread_current ()->pagedir, p->addr,
++ p->frame->base, !p->read_only));
++ else
++ return true;
++}
++
++/* Unlocks a page locked with page_lock(). */
++void
++page_unlock (const void *addr)
++{
++ struct page *p = page_for_addr (addr);
++ ASSERT (p != NULL);
++ frame_unlock (p->frame);
++}
+Index: src/vm/page.h
+diff -u src/vm/page.h~ src/vm/page.h
+--- src/vm/page.h~
++++ src/vm/page.h
+@@ -0,0 +1,50 @@
++#ifndef VM_PAGE_H
++#define VM_PAGE_H
++
++#include <hash.h>
++#include "devices/disk.h"
++#include "filesys/off_t.h"
++#include "threads/synch.h"
++
++/* Virtual page. */
++struct page
++ {
++ /* Immutable members. */
++ void *addr; /* User virtual address. */
++ bool read_only; /* Read-only page? */
++ struct thread *thread; /* Owning thread. */
++
++ /* Accessed only in owning process context. */
++ struct hash_elem hash_elem; /* struct thread `pages' hash element. */
++
++ /* Set only in owning process context with frame->frame_lock held.
++ Cleared only with scan_lock and frame->frame_lock held. */
++ struct frame *frame; /* Page frame. */
++
++ /* Swap information, protected by frame->frame_lock. */
++ disk_sector_t sector; /* Starting sector of swap area, or -1. */
++
++ /* Memory-mapped file information, protected by frame->frame_lock. */
++ bool private; /* False to write back to file,
++ true to write back to swap. */
++ struct file *file; /* File. */
++ off_t file_offset; /* Offset in file. */
++ off_t file_bytes; /* Bytes to read/write, 1...PGSIZE. */
++ };
++
++void page_exit (void);
++
++struct page *page_allocate (void *, bool read_only);
++void page_deallocate (void *vaddr);
++
++bool page_in (void *fault_addr);
++bool page_out (struct page *);
++bool page_accessed_recently (struct page *);
++
++bool page_lock (const void *, bool will_write);
++void page_unlock (const void *);
++
++hash_hash_func page_hash;
++hash_less_func page_less;
++
++#endif /* vm/page.h */
+Index: src/vm/swap.c
+diff -u src/vm/swap.c~ src/vm/swap.c
+--- src/vm/swap.c~
++++ src/vm/swap.c
+@@ -0,0 +1,85 @@
++#include "vm/swap.h"
++#include <bitmap.h>
++#include <debug.h>
++#include <stdio.h>
++#include "vm/frame.h"
++#include "vm/page.h"
++#include "devices/disk.h"
++#include "threads/synch.h"
++#include "threads/vaddr.h"
++
++/* The swap disk. */
++static struct disk *swap_disk;
++
++/* Used swap pages. */
++static struct bitmap *swap_bitmap;
++
++/* Protects swap_bitmap. */
++static struct lock swap_lock;
++
++/* Number of sectors per page. */
++#define PAGE_SECTORS (PGSIZE / DISK_SECTOR_SIZE)
++
++/* Sets up swap. */
++void
++swap_init (void)
++{
++ swap_disk = disk_get (1, 1);
++ if (swap_disk == NULL)
++ {
++ printf ("no swap disk--swap disabled\n");
++ swap_bitmap = bitmap_create (0);
++ }
++ else
++ swap_bitmap = bitmap_create (disk_size (swap_disk) / PAGE_SECTORS);
++ if (swap_bitmap == NULL)
++ PANIC ("couldn't create swap bitmap");
++ lock_init (&swap_lock);
++}
++
++/* Swaps in page P, which must have a locked frame
++ (and be swapped out). */
++void
++swap_in (struct page *p)
++{
++ size_t i;
++
++ ASSERT (p->frame != NULL);
++ ASSERT (lock_held_by_current_thread (&p->frame->lock));
++ ASSERT (p->sector != (disk_sector_t) -1);
++
++ for (i = 0; i < PAGE_SECTORS; i++)
++ disk_read (swap_disk, p->sector + i,
++ p->frame->base + i * DISK_SECTOR_SIZE);
++ bitmap_reset (swap_bitmap, p->sector / PAGE_SECTORS);
++ p->sector = (disk_sector_t) -1;
++}
++
++/* Swaps out page P, which must have a locked frame. */
++bool
++swap_out (struct page *p)
++{
++ size_t slot;
++ size_t i;
++
++ ASSERT (p->frame != NULL);
++ ASSERT (lock_held_by_current_thread (&p->frame->lock));
++
++ lock_acquire (&swap_lock);
++ slot = bitmap_scan_and_flip (swap_bitmap, 0, 1, false);
++ lock_release (&swap_lock);
++ if (slot == BITMAP_ERROR)
++ return false;
++
++ p->sector = slot * PAGE_SECTORS;
++ for (i = 0; i < PAGE_SECTORS; i++)
++ disk_write (swap_disk, p->sector + i,
++ p->frame->base + i * DISK_SECTOR_SIZE);
++
++ p->private = false;
++ p->file = NULL;
++ p->file_offset = 0;
++ p->file_bytes = 0;