Hard-links, via sys_link()
[akaros.git] / kern / src / page_alloc.c
index f6a43c2..c2a45b1 100644 (file)
@@ -1,9 +1,9 @@
-/* Copyright (c) 2009 The Regents of the University  of California. 
+/* Copyright (c) 2009, 2010 The Regents of the University  of California. 
  * See the COPYRIGHT files at the top of this source tree for full 
  * license information.
  * 
  * Kevin Klues <klueska@cs.berkeley.edu>    
- */
+ * Barret Rhoden <brho@cs.berkeley.edu> */
 
 #ifdef __SHARC__
 #pragma nosharc
@@ -25,15 +25,23 @@ static void __page_incref(page_t *CT(1) page);
 static error_t __page_alloc_specific(page_t** page, size_t ppn);
 static error_t __page_free(page_t *CT(1) page);
 
+#ifdef __CONFIG_PAGE_COLORING__
+#define NUM_KERNEL_COLORS 8
+#else
+#define NUM_KERNEL_COLORS 1
+#endif
+
+
 // Global list of colors allocated to the general purpose memory allocator
 uint8_t* global_cache_colors_map;
+size_t global_next_color = 0;
 
 void colored_page_alloc_init()
 {
        global_cache_colors_map = 
               kmalloc(BYTES_FOR_BITMASK(llc_cache->num_colors), 0);
        CLR_BITMASK(global_cache_colors_map, llc_cache->num_colors);
-       for(int i = 0; i < llc_cache->num_colors/2; i++)
+       for(int i = 0; i < llc_cache->num_colors/NUM_KERNEL_COLORS; i++)
                cache_color_alloc(llc_cache, global_cache_colors_map);
 }
 
@@ -59,7 +67,7 @@ static void __page_clear(page_t *SAFE page)
        /* Allocate a page from that color */                                   \
        if(i < (base_color+range)) {                                            \
                *page = LIST_FIRST(&colored_page_free_list[i]);                     \
-               LIST_REMOVE(*page, page_link);                                      \
+               LIST_REMOVE(*page, pg_link);                                      \
                __page_clear(*page);                                                \
                return i;                                                           \
        }                                                                       \
@@ -94,10 +102,10 @@ static ssize_t __colored_page_alloc(uint8_t* map, page_t** page,
 static error_t __page_alloc_specific(page_t** page, size_t ppn)
 {
        page_t* sp_page = ppn2page(ppn);
-       if( sp_page->page_ref != 0 )
+       if (atomic_read(&sp_page->pg_refcnt) != 0)
                return -ENOMEM;
        *page = sp_page;
-       LIST_REMOVE(*page, page_link);
+       LIST_REMOVE(*page, pg_link);
 
        __page_clear(*page);
        return 0;
@@ -133,15 +141,14 @@ error_t upage_alloc(struct proc* p, page_t** page, int zero)
 
 error_t kpage_alloc(page_t** page) 
 {
-       static size_t next_color = 0;
        ssize_t ret;
        spin_lock_irqsave(&colored_page_free_list_lock);
-       if((ret = __page_alloc_from_color_range(page, next_color, 
-                                   llc_cache->num_colors)) < 0)
-               ret = __page_alloc_from_color_range(page, 0, next_color);
+       if((ret = __page_alloc_from_color_range(page, global_next_color, 
+                                   llc_cache->num_colors - global_next_color)) < 0)
+               ret = __page_alloc_from_color_range(page, 0, global_next_color);
 
        if(ret >= 0) {
-               next_color = ret;        
+               global_next_color = ret;        
                page_incref(*page);
                ret = ESUCCESS;
        }
@@ -238,7 +245,7 @@ error_t kpage_alloc_specific(page_t** page, size_t ppn)
 
 /*
  * Return a page to the free list.
- * (This function should only be called when pp->page_ref reaches 0.)
+ * (This function should only be called when pp->pg_refcnt reaches 0.)
  * You must hold the page_free list lock before calling this.
  */
 static error_t __page_free(page_t* page) 
@@ -248,7 +255,7 @@ static error_t __page_free(page_t* page)
        LIST_INSERT_HEAD(
           &(colored_page_free_list[get_page_color(page2ppn(page), llc_cache)]),
           page,
-          page_link
+          pg_link
        );
 
        return ESUCCESS;
@@ -264,11 +271,11 @@ error_t page_free(page_t *SAFE page)
 }
 
 /*
- * Check if a page with the given pyhysical page # is free
+ * Check if a page with the given physical page # is free
  */
 int page_is_free(size_t ppn) {
        page_t* page = ppn2page(ppn);
-       if( page->page_ref == 0 )
+       if (atomic_read(&page->pg_refcnt) == 0)
                return TRUE;
        return FALSE;
 }
@@ -281,9 +288,10 @@ void page_incref(page_t *page)
        __page_incref(page);
 }
 
+/* TODO: (REF) poor refcnting */
 void __page_incref(page_t *page)
 {
-       page->page_ref++;
+       atomic_inc(&page->pg_refcnt);
 }
 
 /*
@@ -300,14 +308,17 @@ void page_decref(page_t *page)
 /*
  * Decrement the reference count on a page,
  * freeing it if there are no more refs.
+ *
+ * TODO: (REF) this is insufficient protection (poor use of atomics, etc).
  */
 static void __page_decref(page_t *page)
 {
-       if (page->page_ref == 0) {
+       if (atomic_read(&page->pg_refcnt) == 0) {
                panic("Trying to Free already freed page: %d...\n", page2ppn(page));
                return;
        }
-       if (--page->page_ref == 0)
+       atomic_dec(&page->pg_refcnt);
+       if (atomic_read(&page->pg_refcnt) == 0)
                __page_free(page);
 }
 
@@ -316,7 +327,7 @@ static void __page_decref(page_t *page)
  */
 void page_setref(page_t *page, size_t val)
 {
-       page->page_ref = val;
+       atomic_set(&page->pg_refcnt, val);
 }
 
 /*
@@ -324,6 +335,25 @@ void page_setref(page_t *page, size_t val)
  */
 size_t page_getref(page_t *page)
 {
-       return page->page_ref;
+       return atomic_read(&page->pg_refcnt);
 }
 
+/* Attempts to get a lock on the page for IO operations.  If it is already
+ * locked, it will block the thread until it is unlocked. */
+void lock_page(struct page *page)
+{
+       /* TODO: (BLK) actually do something!  And this has a race!  Not a big deal
+        * right now, since the only users of this are serialized, but once we have
+        * any sort of real IO, this will be an issue. */
+       assert(!(page->pg_flags & PG_LOCKED));
+       page->pg_flags |= PG_LOCKED;
+}
+
+/* Unlocks the page, and wakes up whoever is waiting on the lock */
+void unlock_page(struct page *page)
+{
+       /* TODO: (BLK) actually do something!  However this unlock works, it will
+        * need to know who to unlock, and it will have to be called in response to
+        * a basic interrupt...  */
+       page->pg_flags &= ~PG_LOCKED;
+}