Commit | Line | Data |
---|---|---|
faca2ef7 DM |
1 | /* |
2 | * tmem.h | |
3 | * | |
4 | * Transcendent memory | |
5 | * | |
6 | * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. | |
7 | */ | |
8 | ||
9 | #ifndef _TMEM_H_ | |
10 | #define _TMEM_H_ | |
11 | ||
12 | #include <linux/types.h> | |
13 | #include <linux/highmem.h> | |
14 | #include <linux/hash.h> | |
15 | #include <linux/atomic.h> | |
16 | ||
17 | /* | |
18 | * These are defined by the Xen<->Linux ABI so should remain consistent | |
19 | */ | |
20 | #define TMEM_POOL_PERSIST 1 | |
21 | #define TMEM_POOL_SHARED 2 | |
22 | #define TMEM_POOL_PRECOMPRESSED 4 | |
23 | #define TMEM_POOL_PAGESIZE_SHIFT 4 | |
24 | #define TMEM_POOL_PAGESIZE_MASK 0xf | |
25 | #define TMEM_POOL_RESERVED_BITS 0x00ffff00 | |
26 | ||
27 | /* | |
28 | * sentinels have proven very useful for debugging but can be removed | |
29 | * or disabled before final merge. | |
30 | */ | |
31 | #undef SENTINELS | |
32 | #ifdef SENTINELS | |
33 | #define DECL_SENTINEL uint32_t sentinel; | |
34 | #define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL) | |
35 | #define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL) | |
36 | #define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL) | |
37 | #define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL) | |
38 | #else | |
39 | #define DECL_SENTINEL | |
40 | #define SET_SENTINEL(_x, _y) do { } while (0) | |
41 | #define INVERT_SENTINEL(_x, _y) do { } while (0) | |
42 | #define ASSERT_SENTINEL(_x, _y) do { } while (0) | |
43 | #define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0) | |
44 | #endif | |
45 | ||
46 | #define ASSERT_SPINLOCK(_l) lockdep_assert_held(_l) | |
47 | ||
48 | /* | |
49 | * A pool is the highest-level data structure managed by tmem and | |
50 | * usually corresponds to a large independent set of pages such as | |
51 | * a filesystem. Each pool has an id, and certain attributes and counters. | |
52 | * It also contains a set of hash buckets, each of which contains an rbtree | |
53 | * of objects and a lock to manage concurrency within the pool. | |
54 | */ | |
55 | ||
56 | #define TMEM_HASH_BUCKET_BITS 8 | |
57 | #define TMEM_HASH_BUCKETS (1<<TMEM_HASH_BUCKET_BITS) | |
58 | ||
59 | struct tmem_hashbucket { | |
60 | struct rb_root obj_rb_root; | |
61 | spinlock_t lock; | |
62 | }; | |
63 | ||
64 | struct tmem_pool { | |
65 | void *client; /* "up" for some clients, avoids table lookup */ | |
66 | struct list_head pool_list; | |
67 | uint32_t pool_id; | |
68 | bool persistent; | |
69 | bool shared; | |
70 | atomic_t obj_count; | |
71 | atomic_t refcount; | |
72 | struct tmem_hashbucket hashbucket[TMEM_HASH_BUCKETS]; | |
73 | DECL_SENTINEL | |
74 | }; | |
75 | ||
76 | #define is_persistent(_p) (_p->persistent) | |
77 | #define is_ephemeral(_p) (!(_p->persistent)) | |
78 | ||
79 | /* | |
80 | * An object id ("oid") is large: 192-bits (to ensure, for example, files | |
81 | * in a modern filesystem can be uniquely identified). | |
82 | */ | |
83 | ||
84 | struct tmem_oid { | |
85 | uint64_t oid[3]; | |
86 | }; | |
87 | ||
88 | static inline void tmem_oid_set_invalid(struct tmem_oid *oidp) | |
89 | { | |
90 | oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL; | |
91 | } | |
92 | ||
93 | static inline bool tmem_oid_valid(struct tmem_oid *oidp) | |
94 | { | |
95 | return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL || | |
96 | oidp->oid[2] != -1UL; | |
97 | } | |
98 | ||
99 | static inline int tmem_oid_compare(struct tmem_oid *left, | |
100 | struct tmem_oid *right) | |
101 | { | |
102 | int ret; | |
103 | ||
104 | if (left->oid[2] == right->oid[2]) { | |
105 | if (left->oid[1] == right->oid[1]) { | |
106 | if (left->oid[0] == right->oid[0]) | |
107 | ret = 0; | |
108 | else if (left->oid[0] < right->oid[0]) | |
109 | ret = -1; | |
110 | else | |
111 | return 1; | |
112 | } else if (left->oid[1] < right->oid[1]) | |
113 | ret = -1; | |
114 | else | |
115 | ret = 1; | |
116 | } else if (left->oid[2] < right->oid[2]) | |
117 | ret = -1; | |
118 | else | |
119 | ret = 1; | |
120 | return ret; | |
121 | } | |
122 | ||
123 | static inline unsigned tmem_oid_hash(struct tmem_oid *oidp) | |
124 | { | |
125 | return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2], | |
126 | TMEM_HASH_BUCKET_BITS); | |
127 | } | |
128 | ||
129 | #ifdef CONFIG_RAMSTER | |
130 | struct tmem_xhandle { | |
131 | uint8_t client_id; | |
132 | uint8_t xh_data_cksum; | |
133 | uint16_t xh_data_size; | |
134 | uint16_t pool_id; | |
135 | struct tmem_oid oid; | |
136 | uint32_t index; | |
137 | void *extra; | |
138 | }; | |
139 | ||
140 | static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id, | |
141 | struct tmem_pool *pool, | |
142 | struct tmem_oid *oidp, | |
143 | uint32_t index) | |
144 | { | |
145 | struct tmem_xhandle xh; | |
146 | xh.client_id = client_id; | |
147 | xh.xh_data_cksum = (uint8_t)-1; | |
148 | xh.xh_data_size = (uint16_t)-1; | |
149 | xh.pool_id = pool->pool_id; | |
150 | xh.oid = *oidp; | |
151 | xh.index = index; | |
152 | return xh; | |
153 | } | |
154 | #endif | |
155 | ||
156 | ||
157 | /* | |
158 | * A tmem_obj contains an identifier (oid), pointers to the parent | |
159 | * pool and the rb_tree to which it belongs, counters, and an ordered | |
160 | * set of pampds, structured in a radix-tree-like tree. The intermediate | |
161 | * nodes of the tree are called tmem_objnodes. | |
162 | */ | |
163 | ||
164 | struct tmem_objnode; | |
165 | ||
166 | struct tmem_obj { | |
167 | struct tmem_oid oid; | |
168 | struct tmem_pool *pool; | |
169 | struct rb_node rb_tree_node; | |
170 | struct tmem_objnode *objnode_tree_root; | |
171 | unsigned int objnode_tree_height; | |
172 | unsigned long objnode_count; | |
173 | long pampd_count; | |
174 | #ifdef CONFIG_RAMSTER | |
175 | /* | |
176 | * for current design of ramster, all pages belonging to | |
177 | * an object reside on the same remotenode and extra is | |
178 | * used to record the number of the remotenode so a | |
179 | * flush-object operation can specify it | |
180 | */ | |
181 | void *extra; /* for private use by pampd implementation */ | |
182 | #endif | |
183 | DECL_SENTINEL | |
184 | }; | |
185 | ||
186 | #define OBJNODE_TREE_MAP_SHIFT 6 | |
187 | #define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT) | |
188 | #define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1) | |
189 | #define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) | |
190 | #define OBJNODE_TREE_MAX_PATH \ | |
191 | (OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2) | |
192 | ||
193 | struct tmem_objnode { | |
194 | struct tmem_obj *obj; | |
195 | DECL_SENTINEL | |
196 | void *slots[OBJNODE_TREE_MAP_SIZE]; | |
197 | unsigned int slots_in_use; | |
198 | }; | |
199 | ||
200 | struct tmem_handle { | |
201 | struct tmem_oid oid; /* 24 bytes */ | |
202 | uint32_t index; | |
203 | uint16_t pool_id; | |
204 | uint16_t client_id; | |
205 | }; | |
206 | ||
207 | ||
208 | /* pampd abstract datatype methods provided by the PAM implementation */ | |
209 | struct tmem_pamops { | |
210 | void (*create_finish)(void *, bool); | |
211 | int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *, | |
212 | struct tmem_oid *, uint32_t); | |
213 | int (*get_data_and_free)(char *, size_t *, bool, void *, | |
214 | struct tmem_pool *, struct tmem_oid *, | |
215 | uint32_t); | |
216 | void (*free)(void *, struct tmem_pool *, | |
217 | struct tmem_oid *, uint32_t, bool); | |
218 | #ifdef CONFIG_RAMSTER | |
219 | void (*new_obj)(struct tmem_obj *); | |
220 | void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool); | |
221 | void *(*repatriate_preload)(void *, struct tmem_pool *, | |
222 | struct tmem_oid *, uint32_t, bool *); | |
223 | int (*repatriate)(void *, void *, struct tmem_pool *, | |
224 | struct tmem_oid *, uint32_t, bool, void *); | |
225 | bool (*is_remote)(void *); | |
226 | int (*replace_in_obj)(void *, struct tmem_obj *); | |
227 | #endif | |
228 | }; | |
229 | extern void tmem_register_pamops(struct tmem_pamops *m); | |
230 | ||
231 | /* memory allocation methods provided by the host implementation */ | |
232 | struct tmem_hostops { | |
233 | struct tmem_obj *(*obj_alloc)(struct tmem_pool *); | |
234 | void (*obj_free)(struct tmem_obj *, struct tmem_pool *); | |
235 | struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *); | |
236 | void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *); | |
237 | }; | |
238 | extern void tmem_register_hostops(struct tmem_hostops *m); | |
239 | ||
240 | /* core tmem accessor functions */ | |
241 | extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index, | |
242 | bool, void *); | |
243 | extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index, | |
244 | char *, size_t *, bool, int); | |
245 | extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *, | |
246 | uint32_t index); | |
247 | extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *); | |
248 | extern int tmem_destroy_pool(struct tmem_pool *); | |
249 | extern void tmem_new_pool(struct tmem_pool *, uint32_t); | |
250 | #ifdef CONFIG_RAMSTER | |
251 | extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index, | |
252 | void *); | |
253 | extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *, | |
254 | uint32_t index, struct tmem_obj **, | |
255 | void **); | |
256 | extern void tmem_localify_finish(struct tmem_obj *, uint32_t index, | |
257 | void *, void *, bool); | |
258 | #endif | |
259 | #endif /* _TMEM_H */ |