debuggers.hg

view xen/include/xen/tmem_xen.h @ 20964:a3fa6d444b25

Fix domain reference leaks

Besides two unlikely/rarely hit ones in x86 code, the main offender
was tmh_client_from_cli_id(), which didn't even have a counterpart
(albeit it had a comment correctly saying that it causes d->refcnt to
get incremented). Unfortunately(?) this required a bit of code
restructuring (as I needed to change the code anyway, I also fixed
a couple os missing bounds checks which would sooner or later be
reported as security vulnerabilities), so I would hope Dan could give
it his blessing before it gets applied.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Feb 10 09:18:43 2010 +0000 (2010-02-10)
parents 277bfc2d47b1
children 61372a4f4e76
line source
1 /******************************************************************************
2 * tmem_xen.h
3 *
4 * Xen-specific Transcendent memory
5 *
6 * Copyright (c) 2009, Dan Magenheimer, Oracle Corp.
7 */
9 #ifndef __XEN_TMEM_XEN_H__
10 #define __XEN_TMEM_XEN_H__
12 #include <xen/config.h>
13 #include <xen/mm.h> /* heap alloc/free */
14 #include <xen/xmalloc.h> /* xmalloc/xfree */
15 #include <xen/sched.h> /* struct domain */
16 #include <xen/guest_access.h> /* copy_from_guest */
17 #include <xen/hash.h> /* hash_long */
18 #include <public/tmem.h>
19 #ifdef CONFIG_COMPAT
20 #include <compat/tmem.h>
21 #endif
23 struct tmem_host_dependent_client {
24 struct domain *domain;
25 struct xmem_pool *persistent_pool;
26 };
27 typedef struct tmem_host_dependent_client tmh_client_t;
29 #define IS_PAGE_ALIGNED(addr) \
30 ((void *)((((unsigned long)addr + (PAGE_SIZE - 1)) & PAGE_MASK)) == addr)
31 #define IS_VALID_PAGE(_pi) ( mfn_valid(page_to_mfn(_pi)) )
33 extern struct xmem_pool *tmh_mempool;
34 extern unsigned int tmh_mempool_maxalloc;
35 extern struct page_list_head tmh_page_list;
36 extern spinlock_t tmh_page_list_lock;
37 extern unsigned long tmh_page_list_pages;
38 extern atomic_t freeable_page_count;
40 extern spinlock_t tmem_lock;
41 extern spinlock_t tmem_spinlock;
42 extern rwlock_t tmem_rwlock;
44 extern void tmh_copy_page(char *to, char*from);
45 extern int tmh_init(void);
46 #define tmh_hash hash_long
48 extern void tmh_release_avail_pages_to_host(void);
49 extern void tmh_scrub_page(struct page_info *pi, unsigned int memflags);
51 extern int opt_tmem_compress;
52 static inline int tmh_compression_enabled(void)
53 {
54 return opt_tmem_compress;
55 }
57 extern int opt_tmem_shared_auth;
58 static inline int tmh_shared_auth(void)
59 {
60 return opt_tmem_shared_auth;
61 }
63 extern int opt_tmem;
64 static inline int tmh_enabled(void)
65 {
66 return opt_tmem;
67 }
69 extern int opt_tmem_lock;
71 extern int opt_tmem_flush_dups;
73 /*
74 * Memory free page list management
75 */
77 static inline struct page_info *tmh_page_list_get(void)
78 {
79 struct page_info *pi;
81 spin_lock(&tmh_page_list_lock);
82 if ( (pi = page_list_remove_head(&tmh_page_list)) != NULL )
83 tmh_page_list_pages--;
84 spin_unlock(&tmh_page_list_lock);
85 ASSERT((pi == NULL) || IS_VALID_PAGE(pi));
86 return pi;
87 }
89 static inline void tmh_page_list_put(struct page_info *pi)
90 {
91 ASSERT(IS_VALID_PAGE(pi));
92 spin_lock(&tmh_page_list_lock);
93 page_list_add(pi, &tmh_page_list);
94 tmh_page_list_pages++;
95 spin_unlock(&tmh_page_list_lock);
96 }
98 static inline unsigned long tmh_avail_pages(void)
99 {
100 return tmh_page_list_pages;
101 }
103 /*
104 * Memory allocation for persistent data
105 */
107 static inline bool_t domain_fully_allocated(struct domain *d)
108 {
109 return ( d->tot_pages >= d->max_pages );
110 }
111 #define tmh_client_memory_fully_allocated(_pool) \
112 domain_fully_allocated(_pool->client->tmh->domain)
114 static inline void *_tmh_alloc_subpage_thispool(struct xmem_pool *cmem_mempool,
115 size_t size, size_t align)
116 {
117 #if 0
118 if ( d->tot_pages >= d->max_pages )
119 return NULL;
120 #endif
121 #ifdef __i386__
122 return _xmalloc(size,align);
123 #else
124 ASSERT( size < tmh_mempool_maxalloc );
125 if ( cmem_mempool == NULL )
126 return NULL;
127 return xmem_pool_alloc(size, cmem_mempool);
128 #endif
129 }
130 #define tmh_alloc_subpage_thispool(_pool, _s, _a) \
131 _tmh_alloc_subpage_thispool(pool->client->tmh->persistent_pool, \
132 _s, _a)
134 static inline void _tmh_free_subpage_thispool(struct xmem_pool *cmem_mempool,
135 void *ptr, size_t size)
136 {
137 #ifdef __i386__
138 xfree(ptr);
139 #else
140 ASSERT( size < tmh_mempool_maxalloc );
141 ASSERT( cmem_mempool != NULL );
142 xmem_pool_free(ptr,cmem_mempool);
143 #endif
144 }
145 #define tmh_free_subpage_thispool(_pool, _p, _s) \
146 _tmh_free_subpage_thispool(_pool->client->tmh->persistent_pool, _p, _s)
148 static inline struct page_info *_tmh_alloc_page_thispool(struct domain *d)
149 {
150 struct page_info *pi;
152 /* note that this tot_pages check is not protected by d->page_alloc_lock,
153 * so may race and periodically fail in donate_page or alloc_domheap_pages
154 * That's OK... neither is a problem, though chatty if log_lvl is set */
155 if ( d->tot_pages >= d->max_pages )
156 return NULL;
158 if ( tmh_page_list_pages )
159 {
160 if ( (pi = tmh_page_list_get()) != NULL )
161 {
162 if ( donate_page(d,pi,0) == 0 )
163 goto out;
164 else
165 tmh_page_list_put(pi);
166 }
167 }
169 pi = alloc_domheap_pages(d,0,MEMF_tmem);
171 out:
172 ASSERT((pi == NULL) || IS_VALID_PAGE(pi));
173 return pi;
174 }
175 #define tmh_alloc_page_thispool(_pool) \
176 _tmh_alloc_page_thispool(_pool->client->tmh->domain)
178 static inline void _tmh_free_page_thispool(struct page_info *pi)
179 {
180 struct domain *d = page_get_owner(pi);
182 ASSERT(IS_VALID_PAGE(pi));
183 if ( (d == NULL) || steal_page(d,pi,0) == 0 )
184 tmh_page_list_put(pi);
185 else
186 {
187 scrub_one_page(pi);
188 ASSERT((pi->count_info & ~(PGC_allocated | 1)) == 0);
189 free_domheap_pages(pi,0);
190 }
191 }
192 #define tmh_free_page_thispool(_pool,_pg) \
193 _tmh_free_page_thispool(_pg)
195 /*
196 * Memory allocation for ephemeral (non-persistent) data
197 */
199 static inline void *tmh_alloc_subpage(void *pool, size_t size,
200 size_t align)
201 {
202 #ifdef __i386__
203 ASSERT( size < PAGE_SIZE );
204 return _xmalloc(size, align);
205 #else
206 ASSERT( size < tmh_mempool_maxalloc );
207 ASSERT( tmh_mempool != NULL );
208 return xmem_pool_alloc(size, tmh_mempool);
209 #endif
210 }
212 static inline void tmh_free_subpage(void *ptr, size_t size)
213 {
214 #ifdef __i386__
215 ASSERT( size < PAGE_SIZE );
216 xfree(ptr);
217 #else
218 ASSERT( size < tmh_mempool_maxalloc );
219 xmem_pool_free(ptr,tmh_mempool);
220 #endif
221 }
223 static inline struct page_info *tmh_alloc_page(void *pool, int no_heap)
224 {
225 struct page_info *pi = tmh_page_list_get();
227 if ( pi == NULL && !no_heap )
228 pi = alloc_domheap_pages(0,0,MEMF_tmem);
229 ASSERT((pi == NULL) || IS_VALID_PAGE(pi));
230 if ( pi != NULL && !no_heap )
231 atomic_inc(&freeable_page_count);
232 return pi;
233 }
235 static inline void tmh_free_page(struct page_info *pi)
236 {
237 ASSERT(IS_VALID_PAGE(pi));
238 tmh_page_list_put(pi);
239 atomic_dec(&freeable_page_count);
240 }
242 static inline unsigned int tmem_subpage_maxsize(void)
243 {
244 return tmh_mempool_maxalloc;
245 }
247 static inline unsigned long tmh_freeable_pages(void)
248 {
249 return tmh_avail_pages() + _atomic_read(freeable_page_count);
250 }
252 static inline unsigned long tmh_free_mb(void)
253 {
254 return (tmh_avail_pages() + total_free_pages()) >> (20 - PAGE_SHIFT);
255 }
257 /*
258 * Memory allocation for "infrastructure" data
259 */
261 static inline void *tmh_alloc_infra(size_t size, size_t align)
262 {
263 return _xmalloc(size,align);
264 }
266 static inline void tmh_free_infra(void *p)
267 {
268 return xfree(p);
269 }
271 #define tmh_lock_all opt_tmem_lock
272 #define tmh_flush_dups opt_tmem_flush_dups
273 #define tmh_called_from_tmem(_memflags) (_memflags & MEMF_tmem)
275 /* "Client" (==domain) abstraction */
277 struct client;
278 typedef domid_t cli_id_t;
279 typedef struct domain tmh_cli_ptr_t;
280 typedef struct page_info pfp_t;
282 extern tmh_client_t *tmh_client_init(cli_id_t);
283 extern void tmh_client_destroy(tmh_client_t *);
285 /* this appears to be unreliable when a domain is being shut down */
286 static inline struct client *tmh_client_from_cli_id(cli_id_t cli_id)
287 {
288 struct domain *d = get_domain_by_id(cli_id); /* incs d->refcnt! */
289 if (d == NULL)
290 return NULL;
291 return (struct client *)(d->tmem);
292 }
294 static inline void tmh_client_put(tmh_client_t *tmh)
295 {
296 put_domain(tmh->domain);
297 }
299 static inline struct client *tmh_client_from_current(void)
300 {
301 return (struct client *)(current->domain->tmem);
302 }
304 #define tmh_client_is_dying(_client) (!!_client->tmh->domain->is_dying)
306 static inline cli_id_t tmh_get_cli_id_from_current(void)
307 {
308 return current->domain->domain_id;
309 }
311 static inline tmh_cli_ptr_t *tmh_get_cli_ptr_from_current(void)
312 {
313 return current->domain;
314 }
316 static inline void tmh_set_client_from_id(struct client *client,
317 tmh_client_t *tmh, cli_id_t cli_id)
318 {
319 struct domain *d = get_domain_by_id(cli_id);
320 d->tmem = client;
321 tmh->domain = d;
322 }
324 static inline bool_t tmh_current_is_privileged(void)
325 {
326 return IS_PRIV(current->domain);
327 }
329 /* these typedefs are in the public/tmem.h interface
330 typedef XEN_GUEST_HANDLE(void) cli_mfn_t;
331 typedef XEN_GUEST_HANDLE(char) cli_va_t;
332 */
333 typedef XEN_GUEST_HANDLE(tmem_op_t) tmem_cli_op_t;
335 static inline int tmh_get_tmemop_from_client(tmem_op_t *op, tmem_cli_op_t uops)
336 {
337 #ifdef CONFIG_COMPAT
338 if ( is_pv_32on64_vcpu(current) )
339 {
340 int rc;
341 enum XLAT_tmem_op_u u;
342 tmem_op_compat_t cop;
344 rc = copy_from_guest(&cop, guest_handle_cast(uops, void), 1);
345 if ( rc )
346 return rc;
347 switch ( cop.cmd )
348 {
349 case TMEM_NEW_POOL: u = XLAT_tmem_op_u_new; break;
350 case TMEM_CONTROL: u = XLAT_tmem_op_u_ctrl; break;
351 case TMEM_AUTH: u = XLAT_tmem_op_u_new; break;
352 case TMEM_RESTORE_NEW:u = XLAT_tmem_op_u_new; break;
353 default: u = XLAT_tmem_op_u_gen ; break;
354 }
355 #define XLAT_tmem_op_HNDL_u_ctrl_buf(_d_, _s_) \
356 guest_from_compat_handle((_d_)->u.ctrl.buf, (_s_)->u.ctrl.buf)
357 XLAT_tmem_op(op, &cop);
358 #undef XLAT_tmem_op_HNDL_u_ctrl_buf
359 return 0;
360 }
361 #endif
362 return copy_from_guest(op, uops, 1);
363 }
365 static inline void tmh_copy_to_client_buf_offset(tmem_cli_va_t clibuf, int off,
366 char *tmembuf, int len)
367 {
368 copy_to_guest_offset(clibuf,off,tmembuf,len);
369 }
371 #define TMH_CLI_ID_NULL ((cli_id_t)((domid_t)-1L))
373 #define tmh_cli_id_str "domid"
374 #define tmh_client_str "domain"
376 extern int tmh_decompress_to_client(tmem_cli_mfn_t,void*,size_t,void*);
378 extern int tmh_compress_from_client(tmem_cli_mfn_t,void**,size_t *,void*);
380 extern int tmh_copy_from_client(pfp_t *pfp,
381 tmem_cli_mfn_t cmfn, uint32_t tmem_offset,
382 uint32_t pfn_offset, uint32_t len, void *cva);
384 extern int tmh_copy_to_client(tmem_cli_mfn_t cmfn, pfp_t *pfp,
385 uint32_t tmem_offset, uint32_t pfn_offset, uint32_t len, void *cva);
388 #define TMEM_PERF
389 #ifdef TMEM_PERF
390 #define DECL_CYC_COUNTER(x) \
391 uint64_t x##_sum_cycles = 0, x##_count = 0; \
392 uint32_t x##_min_cycles = 0x7fffffff, x##_max_cycles = 0;
393 #define EXTERN_CYC_COUNTER(x) \
394 extern uint64_t x##_sum_cycles, x##_count; \
395 extern uint32_t x##_min_cycles, x##_max_cycles;
396 #define DECL_LOCAL_CYC_COUNTER(x) \
397 int64_t x##_start = 0
398 #define START_CYC_COUNTER(x) x##_start = get_cycles()
399 #define DUP_START_CYC_COUNTER(x,y) x##_start = y##_start
400 /* following might race, but since its advisory only, don't care */
401 #define END_CYC_COUNTER(x) \
402 do { \
403 x##_start = get_cycles() - x##_start; \
404 if (x##_start > 0 && x##_start < 1000000000) { \
405 x##_sum_cycles += x##_start; x##_count++; \
406 if ((uint32_t)x##_start < x##_min_cycles) x##_min_cycles = x##_start; \
407 if ((uint32_t)x##_start > x##_max_cycles) x##_max_cycles = x##_start; \
408 } \
409 } while (0)
410 #define END_CYC_COUNTER_CLI(x,y) \
411 do { \
412 x##_start = get_cycles() - x##_start; \
413 if (x##_start > 0 && x##_start < 1000000000) { \
414 x##_sum_cycles += x##_start; x##_count++; \
415 if ((uint32_t)x##_start < x##_min_cycles) x##_min_cycles = x##_start; \
416 if ((uint32_t)x##_start > x##_max_cycles) x##_max_cycles = x##_start; \
417 y->total_cycles += x##_start; \
418 } \
419 } while (0)
420 #define RESET_CYC_COUNTER(x) { x##_sum_cycles = 0, x##_count = 0; \
421 x##_min_cycles = 0x7fffffff, x##_max_cycles = 0; }
422 #define SCNPRINTF_CYC_COUNTER(buf,size,x,tag) \
423 scnprintf(buf,size, \
424 tag"n:%"PRIu64","tag"t:%"PRIu64","tag"x:%"PRId32","tag"m:%"PRId32",", \
425 x##_count,x##_sum_cycles,x##_max_cycles,x##_min_cycles)
426 #else
427 #define DECL_CYC_COUNTER(x)
428 #define EXTERN_CYC_COUNTER(x) \
429 extern uint64_t x##_sum_cycles, x##_count; \
430 extern uint32_t x##_min_cycles, x##_max_cycles;
431 #define DECL_LOCAL_CYC_COUNTER(x) do { } while (0)
432 #define START_CYC_COUNTER(x) do { } while (0)
433 #define DUP_START_CYC_COUNTER(x) do { } while (0)
434 #define END_CYC_COUNTER(x) do { } while (0)
435 #define SCNPRINTF_CYC_COUNTER(buf,size,x,tag) (0)
436 #define RESET_CYC_COUNTER(x) do { } while (0)
437 #endif
439 #endif /* __XEN_TMEM_XEN_H__ */