From e61e868b265efe2f6d51079373588d639fc54d59 Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 21 Jun 2012 18:14:58 +0200 Subject: full mmap implementation --- vm/mmap.c | 91 +++++++++++++++++++++++++++++++++++++++++++++------------------ vm/mmap.h | 13 ++++----- vm/page.c | 21 ++++++++++++--- vm/page.h | 1 + 4 files changed, 91 insertions(+), 35 deletions(-) (limited to 'vm') diff --git a/vm/mmap.c b/vm/mmap.c index 9e7ae47..55ee91b 100644 --- a/vm/mmap.c +++ b/vm/mmap.c @@ -1,4 +1,6 @@ #include +#include "userprog/pagedir.h" +#include "userprog/process.h" #include "filesys/file.h" #include "threads/thread.h" #include "threads/vaddr.h" @@ -23,18 +25,20 @@ mmap_table_init (struct mmap_table *table) return true; } -/* frees the content of mmap table */ +/* closes all mapped files and frees the content of the table */ void mmap_table_free (struct mmap_table *table) { - //TODO + mapid_t id; + for (id = 0; id <= table->id_max; id++) + mmap_table_remove (table, id); palloc_free_page (table->ids); } -/* inserts a new mmap entry in the mmap table +/* inserts a new mmap entry in the mmap table. returns -1 if entry is invalid or already in the table */ mapid_t -mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, +mmap_table_insert (struct mmap_table *table, uint8_t *upage, struct file *file, off_t len) { off_t ofs = 0; @@ -46,43 +50,49 @@ mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, if (table->id_free >= table->id_cap) return -1; + /* create mmap table entry */ mme = malloc (sizeof *mme); if (mme == NULL) return -1; - mapid = table->id_free++; - mme->addr = addr; + mme->upage = upage; mme->file = file; - table->ids[mapid] = mme; + mme->pages = 0; /* create needed pages in page table */ while (len > 0) { page_read_bytes = (len < PGSIZE) ? len : PGSIZE; - if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs, - addr, page_read_bytes, true)) + upage, page_read_bytes, true)) return -1; /* Advance. */ - len -= PGSIZE; - ofs += page_read_bytes; - addr += PGSIZE; + len -= PGSIZE; + ofs += page_read_bytes; + upage += PGSIZE; + mme->pages++; } + /* insert entry into our table */ + mapid = table->id_free++; + table->ids[mapid] = mme; + /* update index of free/max mapid index */ if (mapid > table->id_max) table->id_max = mapid; while (table->ids[table->id_free] != NULL) - { - table->id_free++; - if (table->id_free >= table->id_cap) - break; - } + { + table->id_free++; + if (table->id_free >= table->id_cap) + break; + } return mapid; } +/* get the mmap table entry associated with the given map id. + return NULL if no mapping is associated with the given id */ static struct mmap_table_entry * mmap_table_get (struct mmap_table *table, mapid_t mapid) { @@ -91,26 +101,57 @@ mmap_table_get (struct mmap_table *table, mapid_t mapid) return table->ids[mapid]; } +/* remove the entry associated with the given map id from the mmap table. + flushes all dirty/modified pages back to disk. return true if successful */ bool mmap_table_remove (struct mmap_table *table, mapid_t mapid) { + struct page_table_entry *pte; + off_t ofs = 0; + struct thread *thread = thread_current (); struct mmap_table_entry *mme = mmap_table_get(table, mapid); if (mme == NULL) return false; - table->ids[mapid] = NULL; + /* fetch pages needed by mapped file and check whether the page is dirty */ + while (mme->pages-- > 0) + { + pte = page_table_remove (&thread->page_table, mme->upage + ofs); + if (pte != NULL && pte->loaded && + pagedir_is_dirty (thread->pagedir, pte->upage)) + { + /* write modified page back to disk */ + ASSERT (pte->segment.file == mme->file); + process_lock_filesys (); + file_seek (pte->segment.file, pte->segment.ofs); + file_write (pte->segment.file, pte->upage, pte->segment.read_bytes); + process_unlock_filesys (); + } + + if (pte != NULL) + free (pte); + + ofs += PGSIZE; + } + + /* close the file */ + process_lock_filesys (); + file_close (mme->file); + process_unlock_filesys (); - //TODO + /* remove mmap entry from mmap table */ + free (mme); + table->ids[mapid] = NULL; - /* update index of free/max file descriptor index */ + /* update index of free/max mapid index */ if (mapid < table->id_free) table->id_free = mapid; while (table->ids[table->id_max] == NULL) - { - table->id_max--; - if (table->id_max < 0) - break; - } + { + table->id_max--; + if (table->id_max < 0) + break; + } return true; } diff --git a/vm/mmap.h b/vm/mmap.h index bee364e..09276a7 100644 --- a/vm/mmap.h +++ b/vm/mmap.h @@ -10,21 +10,22 @@ struct mmap_table { struct mmap_table_entry **ids; - int id_free; /* lowest-index free */ - int id_max; /* highest-index used */ - int id_cap; /* mmap table capacity */ + int id_free; /* lowest-index free */ + int id_max; /* highest-index used */ + int id_cap; /* mmap table capacity */ }; /* a single entry in the mmap table */ struct mmap_table_entry { - void *addr; - struct file *file; + uint8_t *upage; /* virtual address of first page of mmapped file */ + struct file *file; /* file handle */ + int pages; /* number of pages the mapping needs */ }; bool mmap_table_init (struct mmap_table *table); void mmap_table_free (struct mmap_table *table); -mapid_t mmap_table_insert (struct mmap_table *table, void *addr, +mapid_t mmap_table_insert (struct mmap_table *table, uint8_t *upage, struct file *file, off_t len); bool mmap_table_remove (struct mmap_table *table, mapid_t mapping); diff --git a/vm/page.c b/vm/page.c index 2853497..98120e5 100644 --- a/vm/page.c +++ b/vm/page.c @@ -28,7 +28,7 @@ page_table_hash (const struct hash_elem *e, void *aux UNUSED) return hash_bytes (&pte->upage, sizeof pte->upage); } -/* page table comperator needed by the hash table implementation +/* page table comperator needed by the hash table implementation. returns true if A is less than B, or false if A is greater than or equal to B */ static bool @@ -55,7 +55,7 @@ page_table_entry_free (struct hash_elem *e, void *aux UNUSED) free (pte); } -/* inserts a new entry into the page table +/* inserts a new entry into the page table. returns false if entry is invalid or already in the table */ static bool page_table_insert (struct hash *ht, struct page_table_entry *pte) @@ -65,7 +65,7 @@ page_table_insert (struct hash *ht, struct page_table_entry *pte) return (hash_insert (ht, &pte->elem) == NULL); } -/* inserts a new entry of type segment into the page table +/* inserts a new entry of type segment into the page table. returns false if entry is invalid or already in the table */ bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, @@ -96,7 +96,20 @@ page_table_fetch (struct hash *ht, void *upage) return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); } -/* load the page referenced by the page table entry +/* remove an entry from the page table. returns the element or NULL if not found. + the caller is responsible for freeing the element! */ +struct page_table_entry * +page_table_remove (struct hash *ht, void *upage) +{ + struct page_table_entry pte; + struct hash_elem *e; + + pte.upage = upage; + e = hash_delete (ht, &pte.elem); + return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); +} + +/* load the page referenced by the page table entry. returns true on success or already loaded, false otherwise */ bool page_load (struct page_table_entry *pte) diff --git a/vm/page.h b/vm/page.h index da1398c..c78ab65 100644 --- a/vm/page.h +++ b/vm/page.h @@ -26,6 +26,7 @@ struct page_table_entry void page_table_init (struct hash *ht); void page_table_free (struct hash *ht); struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); +struct page_table_entry *page_table_remove (struct hash *ht, void *upage); bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, bool writable); bool page_load (struct page_table_entry *pte); -- cgit v1.2.3