Merge branch 'dev' into new_dpf
[kernel/swap-modules.git] / driver / sspt / sspt_file.c
1 #include "sspt_file.h"
2 #include "sspt_page.h"
3 #include <linux/slab.h>
4 #include <linux/list.h>
5 #include <linux/hash.h>
6
7
8 static int calculation_hash_bits(int cnt)
9 {
10         int bits;
11         for (bits = 1; cnt >>= 1; ++bits);
12
13         return bits;
14 }
15
16 struct sspt_file *sspt_file_create(const char *path, struct dentry *dentry, int page_cnt)
17 {
18         struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
19
20         if (obj) {
21                 int i, table_size;
22                 obj->path = path;
23                 obj->dentry = dentry;
24                 obj->loaded = 0;
25                 obj->vm_start = 0;
26                 obj->vm_end = 0;
27
28                 obj->page_probes_hash_bits = calculation_hash_bits(page_cnt);//PAGE_PROBES_HASH_BITS;
29                 table_size = (1 << obj->page_probes_hash_bits);
30
31                 obj->page_probes_table = kmalloc(sizeof(*obj->page_probes_table)*table_size, GFP_ATOMIC);
32
33                 for (i = 0; i < table_size; ++i) {
34                         INIT_HLIST_HEAD(&obj->page_probes_table[i]);
35                 }
36         }
37
38         return obj;
39 }
40
41 void sspt_file_free(struct sspt_file *file)
42 {
43         struct hlist_node *p, *n;
44         struct hlist_head *head;
45         struct sspt_page *page;
46         int i, table_size = (1 << file->page_probes_hash_bits);
47
48         for (i = 0; i < table_size; ++i) {
49                 head = &file->page_probes_table[i];
50                 hlist_for_each_entry_safe(page, p, n, head, hlist) {
51                         hlist_del(&page->hlist);
52                         sspt_page_free(page);
53                 }
54         }
55
56         kfree(file->page_probes_table);
57         kfree(file);
58 }
59
60 static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
61 {
62         hlist_add_head(&page->hlist, &file->page_probes_table[hash_ptr(page->offset, file->page_probes_hash_bits)]);
63 }
64
65 struct sspt_file *sspt_file_copy(const struct sspt_file *file)
66 {
67         struct sspt_file *file_out;
68
69         if (file == NULL) {
70                 printk("### WARNING: file_p == NULL\n");
71                 return NULL;
72         }
73
74         file_out = kmalloc(sizeof(*file_out), GFP_ATOMIC);
75         if (file_out) {
76                 struct sspt_page *page = NULL;
77                 struct hlist_node *node = NULL;
78                 struct hlist_head *head = NULL;
79                 int i, table_size;
80                 INIT_LIST_HEAD(&file_out->list);
81                 file_out->dentry = file->dentry;
82                 file_out->path = file->path;
83                 file_out->loaded = 0;
84                 file_out->vm_start = 0;
85                 file_out->vm_end = 0;
86
87                 file_out->page_probes_hash_bits = file->page_probes_hash_bits;
88                 table_size = (1 << file_out->page_probes_hash_bits);
89
90                 file_out->page_probes_table =
91                                 kmalloc(sizeof(*file_out->page_probes_table)*table_size, GFP_ATOMIC);
92
93                 for (i = 0; i < table_size; ++i) {
94                         INIT_HLIST_HEAD(&file_out->page_probes_table[i]);
95                 }
96
97                 // copy pages
98                 for (i = 0; i < table_size; ++i) {
99                         head = &file->page_probes_table[i];
100                         hlist_for_each_entry(page, node, head, hlist) {
101                                 sspt_add_page(file_out, sspt_page_copy(page));
102                         }
103                 }
104         }
105
106         return file_out;
107 }
108
109 static struct sspt_page *sspt_find_page(struct sspt_file *file, unsigned long offset)
110 {
111         struct hlist_node *node;
112         struct hlist_head *head;
113         struct sspt_page *page;
114
115         head = &file->page_probes_table[hash_ptr(offset, file->page_probes_hash_bits)];
116         hlist_for_each_entry(page, node, head, hlist) {
117                 if (page->offset == offset) {
118                         return page;
119                 }
120         }
121
122         return NULL;
123 }
124
125 static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file, unsigned long offset)
126 {
127         struct sspt_page *page = sspt_find_page(file, offset);
128
129         if (page == NULL) {
130                 page = sspt_page_create(offset);
131                 sspt_add_page(file, page);
132         }
133
134         return page;
135 }
136
137 struct sspt_page *sspt_find_page_mapped(struct sspt_file *file, unsigned long page)
138 {
139         unsigned long offset;
140
141         if (file->vm_start > page || file->vm_end < page) {
142                 // TODO: or panic?!
143                 printk("ERROR: file_p[vm_start..vm_end] <> page: file_p[vm_start=%x, vm_end=%x, path=%s, d_iname=%s] page=%x\n",
144                                 file->vm_start, file->vm_end, file->path, file->dentry->d_iname, page);
145                 return NULL;
146         }
147
148         offset = page - file->vm_start;
149
150         return sspt_find_page(file, offset);
151 }
152
153 void sspt_file_add_ip(struct sspt_file *file, struct ip_data *ip_d)
154 {
155         unsigned long offset = ip_d->offset & PAGE_MASK;
156         struct sspt_page *page = sspt_find_page_or_new(file, offset);
157
158         // FIXME: delete ip
159         struct us_ip *ip = create_ip_by_ip_data(ip_d);
160
161         sspt_add_ip(page, ip);
162 }
163
164 struct sspt_page *sspt_get_page(struct sspt_file *file, unsigned long offset_addr)
165 {
166         unsigned long offset = offset_addr & PAGE_MASK;
167         struct sspt_page *page = sspt_find_page_or_new(file, offset);
168
169         spin_lock(&page->lock);
170
171         return page;
172 }
173
174 void sspt_put_page(struct sspt_page *page)
175 {
176         spin_unlock(&page->lock);
177 }