Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / block / fvd-debug.c
blob239a47dcff55b890e164c3b4a5bca524623999bb
1 /*
2 * Copyright (c) 2010-2011 IBM
4 * Authors:
5 * Chunqiang Tang <ctang@us.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2.
8 * See the COPYING file in the top-level directory.
9 */
11 /*=============================================================================
12 * A short description: this module implements debugging functions for
13 * the Fast Virtual Disk (FVD) format.
14 *============================================================================*/
16 #ifndef ENABLE_TRACE_IO
17 # define TRACE_REQUEST(...) do {} while (0)
18 # define TRACE_STORE_IN_FVD(...) do {} while (0)
20 #else
21 /* Monitor IO on a specific sector that triggers bugs. */
22 static inline void debug_sector (int64_t sector_num)
24 if (FALSE) {
25 if (sector_num == ((int64_t) 1023990LL)) {
26 QPAUSE ("right sector");
31 static void TRACE_REQUEST (int do_write, int64_t sector_num, int nb_sectors)
33 if (do_write) {
34 QDEBUG ("TRACE_REQUEST: write sector_num=%" PRId64
35 " nb_sectors=%d\n [ ", sector_num, nb_sectors);
36 } else {
37 QDEBUG ("TRACE_REQUEST: read sector_num=%" PRId64 " nb_sectors=%d\n"
38 "[ ", sector_num, nb_sectors);
41 int64_t end = sector_num + nb_sectors;
42 int64_t sec;
43 for (sec = sector_num; sec < end; sec++) {
44 QDEBUG ("sec%" PRId64 " ", sec);
45 debug_sector (sec);
47 QDEBUG (" ]\n");
50 static void TRACE_STORE_IN_FVD (const char *str, int64_t sector_num,
51 int nb_sectors)
53 QDEBUG ("TRACE_STORE: %s sector_num=%" PRId64 " nb_sectors=%d\n [ ",
54 str, sector_num, nb_sectors);
55 int64_t end = sector_num + nb_sectors;
56 int64_t sec;
57 for (sec = sector_num; sec < end; sec++) {
58 QDEBUG ("sec%" PRId64 " ", sec);
59 debug_sector (sec);
61 QDEBUG (" ]\n");
63 #endif
65 #ifndef FVD_DEBUG
66 # define my_qemu_malloc g_malloc
67 # define my_qemu_mallocz g_malloc0
68 # define my_qemu_blockalign qemu_blockalign
69 # define my_qemu_free g_free
70 # define my_qemu_vfree qemu_vfree
71 # define my_qemu_aio_get qemu_aio_get
72 # define my_qemu_aio_unref qemu_aio_unref
73 # define COPY_UUID(to,from) do {} while (0)
75 #else
76 FILE *__fvd_debug_fp;
77 static unsigned long long int fvd_uuid = 1;
78 static int64_t pending_qemu_malloc = 0;
79 static int64_t pending_qemu_aio_get = 0;
80 static int64_t pending_local_writes = 0;
81 static const char *alloc_file;
82 static int alloc_line;
84 #define my_qemu_malloc(size) \
85 ((void*)(alloc_file=__FILE__, alloc_line=__LINE__, _my_qemu_malloc(size)))
87 #define my_qemu_mallocz(size) \
88 ((void*)(alloc_file=__FILE__, alloc_line=__LINE__, _my_qemu_mallocz(size)))
90 #define my_qemu_blockalign(bs,size) \
91 ((void*)(alloc_file=__FILE__, \
92 alloc_line=__LINE__, \
93 _my_qemu_blockalign(bs,size)))
95 #define my_qemu_aio_get(pool,bs,cb,op) \
96 ((void*)(alloc_file=__FILE__, \
97 alloc_line=__LINE__, \
98 _my_qemu_aio_get(pool,bs,cb,op)))
100 #define my_qemu_free(p) \
101 (alloc_file=__FILE__, alloc_line=__LINE__, _my_qemu_free(p))
103 #define my_qemu_vfree(p) \
104 (alloc_file=__FILE__, alloc_line=__LINE__, _my_qemu_vfree(p))
106 static void COPY_UUID (FvdAIOCB * to, FvdAIOCB * from)
108 if (from) {
109 to->uuid = from->uuid;
110 FVD_DEBUG_ACB (to);
114 #ifdef DEBUG_MEMORY_LEAK
115 # define MAX_TRACER 10485760
116 static int alloc_tracer_used = 1; /* slot 0 is not used. */
117 static void **alloc_tracers = NULL;
119 static void __attribute__ ((constructor)) init_mem_alloc_tracers (void)
121 if (!alloc_tracers) {
122 alloc_tracers = g_malloc0(sizeof(void *) * MAX_TRACER);
126 static void trace_alloc (void *p, size_t size)
128 alloc_tracer_t *t = p;
129 t->magic = FVD_ALLOC_MAGIC;
130 t->alloc_file = alloc_file;
131 t->alloc_line = alloc_line;
132 t->size = size;
134 if (alloc_tracer_used < MAX_TRACER) {
135 t->alloc_tracer = alloc_tracer_used++;
136 alloc_tracers[t->alloc_tracer] = t;
137 QDEBUG ("Allocate memory using tracer%d in %s on line %d.\n",
138 t->alloc_tracer, alloc_file, alloc_line);
139 } else {
140 t->alloc_tracer = 0;
143 /* Set header and footer to detect out-of-range writes. */
144 if (size != (size_t) - 1) {
145 uint8_t *q = (uint8_t *) p;
146 uint64_t *header = (uint64_t *) (q + 512 - sizeof (uint64_t));
147 uint64_t *footer = (uint64_t *) (q + size - 512);
148 *header = FVD_ALLOC_MAGIC;
149 *footer = FVD_ALLOC_MAGIC;
153 static void trace_free (void *p)
155 alloc_tracer_t *t = p;
157 QDEBUG ("Free memory with tracer%d in %s on line %d.\n",
158 t->alloc_tracer, alloc_file, alloc_line);
159 ASSERT (t->magic == FVD_ALLOC_MAGIC && t->alloc_tracer >= 0);
161 /* Check header and footer to detect out-of-range writes. */
162 if (t->size != (size_t) - 1) {
163 uint8_t *q = (uint8_t *) p;
164 uint64_t *header = (uint64_t *) (q + 512 - sizeof (uint64_t));
165 uint64_t *footer = (uint64_t *) (q + t->size - 512);
166 ASSERT (*header == FVD_ALLOC_MAGIC);
167 ASSERT (*footer == FVD_ALLOC_MAGIC);
170 if (t->alloc_tracer) {
171 ASSERT (alloc_tracers[t->alloc_tracer] == t);
172 alloc_tracers[t->alloc_tracer] = NULL;
173 t->alloc_tracer = -INT_MAX;
174 } else {
175 t->alloc_tracer *= -1; /* Guard against double free. */
179 static void dump_alloc_tracers (void)
181 int unfreed = 0;
182 int i;
183 for (i = 1; i < alloc_tracer_used; i++) {
184 if (!alloc_tracers[i]) {
185 continue;
188 unfreed++;
189 alloc_tracer_t *t = alloc_tracers[i];
191 if (t->size == (size_t) - 1) {
192 FvdAIOCB *acb = container_of (alloc_tracers[i], FvdAIOCB, tracer);
193 ASSERT (acb->magic == FVDAIOCB_MAGIC);
194 QDEBUG ("Memory %p with tracer%d allocated in %s on line %d "
195 "(FvdAIOCB acb%llu-%p) is not freed. magic %s\n",
196 alloc_tracers[i], i, t->alloc_file, t->alloc_line,
197 acb->uuid, acb,
198 t->magic == FVD_ALLOC_MAGIC ? "correct" : "wrong");
199 } else {
200 QDEBUG ("Memory %p with tracer%d allocated in %s on line %d is "
201 "not freed. magic %s\n",
202 alloc_tracers[i], i, t->alloc_file, t->alloc_line,
203 t->magic == FVD_ALLOC_MAGIC ? "correct" : "wrong");
205 uint8_t *q = (uint8_t *) t;
206 uint64_t *header = (uint64_t *) (q + 512 - sizeof (uint64_t));
207 uint64_t *footer = (uint64_t *) (q + t->size - 512);
208 ASSERT (*header == FVD_ALLOC_MAGIC);
209 ASSERT (*footer == FVD_ALLOC_MAGIC);
213 QDEBUG ("Unfreed memory allocations: %d\n", unfreed);
215 #endif
217 static inline void *_my_qemu_aio_get (AIOCBInfo *pool, BlockDriverState *bs,
218 BlockDriverCompletionFunc * cb,
219 void *opaque)
221 pending_qemu_aio_get++;
222 FvdAIOCB *acb = (FvdAIOCB *) qemu_aio_get (&fvd_aio_pool, bs, cb, opaque);
223 acb->uuid = ++fvd_uuid;
224 acb->magic = FVDAIOCB_MAGIC;
226 FVD_DEBUG_ACB (acb);
228 #ifdef DEBUG_MEMORY_LEAK
229 trace_alloc (&acb->tracer, -1);
230 #endif
232 return acb;
235 static inline void my_qemu_aio_unref (void *p)
237 pending_qemu_aio_get--;
238 ASSERT (pending_qemu_aio_get >= 0);
240 #ifdef DEBUG_MEMORY_LEAK
241 FvdAIOCB *acb = p;
242 trace_free (&acb->tracer);
243 #endif
245 qemu_aio_unref (p);
248 static inline void *_my_qemu_malloc (size_t size)
250 ASSERT (size > 0);
251 pending_qemu_malloc++;
252 #ifndef DEBUG_MEMORY_LEAK
253 return g_malloc(size);
254 #else
256 size += 1024; /* 512 bytes header and 512 bytes footer. */
257 uint8_t *ret = g_malloc(size);
258 trace_alloc (ret, size);
259 return ret + 512;
260 #endif
263 static inline void *_my_qemu_mallocz (size_t size)
265 ASSERT (size > 0);
266 pending_qemu_malloc++;
267 #ifndef DEBUG_MEMORY_LEAK
268 return g_malloc0(size);
269 #else
271 size += 1024; /* 512 bytes header and 512 bytes footer. */
272 uint8_t *ret = g_malloc0(size);
273 trace_alloc (ret, size);
274 return ret + 512;
275 #endif
278 static inline void *_my_qemu_blockalign (BlockDriverState * bs, size_t size)
280 ASSERT (size > 0);
281 pending_qemu_malloc++;
283 #ifndef DEBUG_MEMORY_LEAK
284 return qemu_blockalign (bs, size);
285 #else
287 size += 1024; /* 512 bytes header and 512 bytes footer. */
288 uint8_t *ret = qemu_blockalign (bs, size);
289 trace_alloc (ret, size);
290 return ret + 512;
291 #endif
294 static inline void _my_qemu_free (void *ptr)
296 pending_qemu_malloc--;
297 ASSERT (pending_qemu_malloc >= 0);
298 #ifndef DEBUG_MEMORY_LEAK
299 g_free(ptr);
300 #else
302 uint8_t *q = ((uint8_t *) ptr) - 512;
303 trace_free (q);
304 g_free(q);
305 #endif
308 static inline void _my_qemu_vfree (void *ptr)
310 pending_qemu_malloc--;
311 ASSERT (pending_qemu_malloc >= 0);
312 #ifndef DEBUG_MEMORY_LEAK
313 qemu_vfree (ptr);
314 #else
316 uint8_t *q = ((uint8_t *) ptr) - 512;
317 trace_free (q);
318 qemu_vfree (q);
319 #endif
322 static void count_pending_requests (BDRVFvdState * s)
324 int m = 0, k = 0;
325 FvdAIOCB *w;
327 QLIST_FOREACH (w, &s->copy_locks, copy_lock.next) {
328 m++;
329 QDEBUG ("copy_lock: acb%llu-%p\n", w->uuid, w);
332 QLIST_FOREACH (w, &s->write_locks, write.next_write_lock) {
333 k++;
334 QDEBUG ("write_lock: acb%llu-%p\n", w->uuid, w);
337 QDEBUG ("Debug_memory_leak: copy_locks=%d write_locks=%d\n", m, k);
340 static void dump_resource_summary (BDRVFvdState * s)
342 #ifdef DEBUG_MEMORY_LEAK
343 dump_alloc_tracers ();
344 #endif
346 QDEBUG ("Resource summary: outstanding_copy_on_read_data=%" PRId64
347 " total_copy_on_read_data=%" PRId64 " total_prefetch_data=%" PRId64
348 " " " pending_qemu_malloc=%" PRId64 " pending_qemu_aio_get=%" PRId64
349 " pending_local_writes=%" PRId64 "\n",
350 s->outstanding_copy_on_read_data, s->total_copy_on_read_data,
351 s->total_prefetch_data, pending_qemu_malloc, pending_qemu_aio_get,
352 pending_local_writes);
353 count_pending_requests (s);
356 /* Monitor processing a specific FvdAIOCB that triggers bugs. */
357 void FVD_DEBUG_ACB (void *p)
359 if (FALSE) {
360 FvdAIOCB *acb = p;
362 /* Is it FvdAIOCB? */
363 if (acb->magic != FVDAIOCB_MAGIC || acb->common.bs->drv != &bdrv_fvd) {
364 /* Is it CompactChildCB? */
365 CompactChildCB *child = p;
366 acb = child->acb;
367 if (acb->magic != FVDAIOCB_MAGIC
368 || acb->common.bs->drv != &bdrv_fvd
369 || (acb->type != OP_LOAD_COMPACT
370 && acb->type != OP_STORE_COMPACT)) {
371 return;
375 if (acb->uuid == 20ULL) {
376 QPAUSE ("Processing the right acb");
381 void init_fvd_debug_fp (void)
383 char buf[256];
384 sprintf (buf, "/tmp/fvd.log-%d", getpid ());
385 if ((__fvd_debug_fp = fopen (buf, "wt")) == NULL) {
386 __fvd_debug_fp = stdout;
389 #endif
391 void fvd_check_memory_usage (void)
393 ASSERT (pending_qemu_malloc == 0);
396 int fvd_get_copy_on_read (BlockDriverState * bs)
398 BDRVFvdState *s = bs->opaque;
399 return s->copy_on_read;
402 void fvd_set_copy_on_read (BlockDriverState * bs, int copy_on_read)
404 BDRVFvdState *s = bs->opaque;
405 s->copy_on_read = copy_on_read;