aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNamhoon Kim <namhoonk@cs.unc.edu>2016-09-23 10:07:04 -0400
committerNamhoon Kim <namhoonk@cs.unc.edu>2016-09-23 10:07:04 -0400
commit1b2c1185069cf723ac4122e7cad99d538f36d973 (patch)
treeb888bd909775aabe98d8805e4c7391916e67cab9
parentd7352bf3c9392104c34b56e2c0756a14db81b68a (diff)
9/23/2016test
-rw-r--r--mm/replication.c575
1 files changed, 575 insertions, 0 deletions
diff --git a/mm/replication.c b/mm/replication.c
new file mode 100644
index 000000000000..aab1553078c8
--- /dev/null
+++ b/mm/replication.c
@@ -0,0 +1,575 @@
1/*
2 * linux/mm/replication.c
3 * pagecache replication
4 */
5#include <linux/init.h>
6#include <linux/mm.h>
7#include <linux/mmzone.h>
8#include <linux/swap.h>
9#include <linux/fs.h>
10#include <linux/pagemap.h>
11#include <linux/page-flags.h>
12#include <linux/pagevec.h>
13#include <linux/gfp.h>
14#include <linux/slab.h>
15#include <linux/radix-tree.h>
16#include <linux/spinlock.h>
17
18#include <litmus/litmus.h>
19
20#include "internal.h"
21
22#define MAX_NUMCPUS 4
23
24static struct kmem_cache *pcache_desc_cachep;
25
26void __init replication_init(void)
27{
28 pcache_desc_cachep = kmem_cache_create("pcache_desc",
29 sizeof(struct pcache_desc), 0, SLAB_PANIC, NULL);
30 printk(KERN_INFO "Page replication initialized.\n");
31}
32
33static struct pcache_desc *alloc_pcache_desc(void)
34{
35 struct pcache_desc *ret;
36
37 /* NOIO because find_get_page_readonly may be called in the IO path */
38 ret = kmem_cache_alloc(pcache_desc_cachep, GFP_ATOMIC);
39 if (ret) {
40 memset(ret, 0, sizeof(struct pcache_desc));
41 /* XXX: should use non-atomic preloads */
42 INIT_RADIX_TREE(&ret->page_tree, GFP_ATOMIC);
43 }
44 return ret;
45}
46
47static void free_pcache_desc(struct pcache_desc *pcd)
48{
49 kmem_cache_free(pcache_desc_cachep, pcd);
50}
51
52/*
53 * Free the struct pcache_desc, and all slaves. The pagecache refcount is
54 * retained for the master (because presumably we're collapsing the replication.
55 *
56 * Returns 1 if any of the slaves had a non-zero mapcount (in which case, we'll
57 * have to unmap them), otherwise returns 0.
58 */
59static int release_pcache_desc(struct pcache_desc *pcd)
60{
61 int ret = 0;
62 int i;
63
64 page_cache_get(pcd->master);
65 for_each_cpu(i, &pcd->cpus_present) {
66 struct page *page;
67
68 page = radix_tree_delete(&pcd->page_tree, i);
69 BUG_ON(!page);
70 if (page != pcd->master) {
71 BUG_ON(PageDirty(page));
72 BUG_ON(!PageUptodate(page));
73 dec_zone_page_state(page, NR_REPL_PAGES);
74 page->mapping = NULL;
75 if (page_mapped(page))
76 ret = 1; /* tell caller to unmap the ptes */
77 }
78 page_cache_release(page);
79 }
80
81 free_pcache_desc(pcd);
82
83 return ret;
84}
85
86#define PCACHE_DESC_BIT 4 /* 1 is used internally by the radix-tree */
87
88static inline int __is_pcache_desc(void *ptr)
89{
90 if ((unsigned long)ptr & PCACHE_DESC_BIT)
91 return 1;
92 return 0;
93}
94
95int is_pcache_desc(void *ptr)
96{
97 return __is_pcache_desc(ptr);
98}
99
100struct pcache_desc *ptr_to_pcache_desc(void *ptr)
101{
102 BUG_ON(!__is_pcache_desc(ptr));
103 return (struct pcache_desc *)((unsigned long)ptr & ~PCACHE_DESC_BIT);
104}
105
106void *pcache_desc_to_ptr(struct pcache_desc *pcd)
107{
108 BUG_ON(__is_pcache_desc(pcd));
109 return (void *)((unsigned long)pcd | PCACHE_DESC_BIT);
110}
111
112/*
113 * Must be called with the page locked and tree_lock held to give a non-racy
114 * answer.
115 */
116static int should_replicate_pcache(struct page *page, struct address_space *mapping,
117 unsigned long offset)
118{
119 umode_t mode;
120
121 if (unlikely(PageSwapCache(page)))
122 return 0;
123printk(KERN_INFO "[Pg %ld] _count = %d, _mapcount = %d\n", page_to_pfn(page), page_count(page), page_mapcount(page));
124 if (page_count(page) != 2 + page_mapcount(page))
125 return 0;
126 smp_rmb();
127 if (!PageUptodate(page) || PageDirty(page) || PageWriteback(page))
128 return 0;
129
130 if (!PagePrivate(page))
131 return 1;
132
133 mode = mapping->host->i_mode;
134 if (S_ISREG(mode) || S_ISBLK(mode))
135 return 1;
136
137 return 0;
138}
139
140/*
141 * Try to convert pagecache coordinate (mapping, offset) (with page residing)
142 * into a replicated pagecache.
143 *
144 * Returns 1 if we leave with a successfully converted pagecache. Otherwise 0.
145 * (note, that return value is racy, so it is a hint only)
146 */
147static int try_to_replicate_pcache(struct page *page, struct address_space *mapping,
148 unsigned long offset)
149{
150 int cpu;
151 void **pslot;
152 struct pcache_desc *pcd;
153 int ret = 0;
154
155 //lock_page(page);
156 if (!trylock_page(page)) {
157printk(KERN_INFO "TRYLOCK_PAGE failed\n");
158 return ret;
159 }
160
161 if (unlikely(!page->mapping))
162 goto out;
163
164 pcd = alloc_pcache_desc();
165 if (!pcd)
166 goto out;
167
168 if (!tsk_rt(current)) {
169 BUG();
170 goto out;
171 }
172
173 cpu = tsk_rt(current)->task_params.cpu;
174
175 pcd->master = page;
176 //cpumask_set_cpu(cpu, &pcd->cpus_present);
177 //if (radix_tree_insert(&pcd->page_tree, cpu, page))
178 // goto out_pcd;
179
180 spin_lock_irq(&mapping->tree_lock);
181
182 /* The non-racy check */
183 if (unlikely(!should_replicate_pcache(page, mapping, offset)))
184 goto out_lock;
185
186 pslot = radix_tree_lookup_slot(&mapping->page_tree, offset);
187
188 /* Already been replicated? Return yes! */
189 if (unlikely(is_pcache_desc(radix_tree_deref_slot(pslot)))) {
190 free_pcache_desc(pcd);
191 ret = 1;
192 goto out_lock;
193 }
194 /*
195 * The page is being held in pagecache and kept unreplicated because
196 * it is locked. The following bugchecks.
197 */
198 BUG_ON(!pslot);
199 BUG_ON(page != radix_tree_deref_slot(pslot));
200 BUG_ON(is_pcache_desc(radix_tree_deref_slot(pslot)));
201
202 radix_tree_replace_slot(pslot, pcache_desc_to_ptr(pcd));
203 radix_tree_tag_set(&mapping->page_tree, offset, PAGECACHE_TAG_REPLICATED);
204 ret = 1;
205
206out_lock:
207 spin_unlock_irq(&mapping->tree_lock);
208out_pcd:
209 if (ret == 0)
210 free_pcache_desc(pcd);
211out: