Converts page_map for bdev usage
[akaros.git] / kern / src / pagemap.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Page mapping: maps an object (inode or block dev) in page size chunks.
6  * Analagous to Linux's "struct address space" */
7
8 #include <pmap.h>
9 #include <atomic.h>
10 #include <radix.h>
11 #include <kref.h>
12 #include <assert.h>
13 #include <stdio.h>
14
15 /* Initializes a PM.  Host should be an *inode or a *bdev (doesn't matter).  The
16  * reference this stores is uncounted. */
17 void pm_init(struct page_map *pm, struct page_map_operations *op, void *host)
18 {
19         pm->pm_bdev = host;                                             /* note the uncounted ref */
20         radix_tree_init(&pm->pm_tree);
21         spinlock_init(&pm->pm_tree_lock);
22         pm->pm_num_pages = 0;                                   /* no pages in a new pm */
23         pm->pm_op = op;
24         pm->pm_flags = 0;
25 }
26
27 /* Looks up the index'th page in the page map, returning an incref'd reference,
28  * or 0 if it was not in the map. */
29 struct page *pm_find_page(struct page_map *pm, unsigned long index)
30 {
31         spin_lock(&pm->pm_tree_lock);
32         struct page *page = (struct page*)radix_lookup(&pm->pm_tree, index);
33         if (page)
34                 page_incref(page);
35         spin_unlock(&pm->pm_tree_lock);
36         return page;
37 }
38
39 /* Attempts to insert the page into the page_map, returns 0 for success, or an
40  * error code if there was one already (EEXIST) or we ran out of memory
41  * (ENOMEM).  On success, this will preemptively lock the page, and will also
42  * store a reference to the page in the pm. */
43 int pm_insert_page(struct page_map *pm, unsigned long index, struct page *page)
44 {
45         int error = 0;
46         spin_lock(&pm->pm_tree_lock);
47         error = radix_insert(&pm->pm_tree, index, page);
48         if (!error) {
49                 page_incref(page);
50                 page->pg_flags |= PG_LOCKED | PG_BUFFER;
51                 page->pg_mapping = pm;
52                 page->pg_index = index;
53                 pm->pm_num_pages++;
54         }
55         spin_unlock(&pm->pm_tree_lock);
56         return error;
57 }
58
59 /* Removes the page, including its reference.  Not sure yet what interface we
60  * want to this (pm and index or page), and this has never been used.  There are
61  * also issues with when you want to call this, since a page in the cache may be
62  * mmap'd by someone else. */
63 int pm_remove_page(struct page_map *pm, struct page *page)
64 {
65         void *retval;
66         warn("pm_remove_page() hasn't been thought through or tested.");
67         /* TODO: check for dirty pages, don't let them be removed right away.  Need
68          * to schedule them for writeback, and then remove them later (callback). */
69         spin_lock(&pm->pm_tree_lock);
70         retval = radix_delete(&pm->pm_tree, page->pg_index);
71         spin_unlock(&pm->pm_tree_lock);
72         assert(retval == (void*)page);
73         page_decref(page);
74         pm->pm_num_pages--;
75         return 0;
76 }