2 * Copyright (c) 2010-2011 IBM
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.
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)
21 /* Monitor IO on a specific sector that triggers bugs. */
22 static inline void debug_sector (int64_t sector_num
)
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
)
34 QDEBUG ("TRACE_REQUEST: write sector_num=%" PRId64
35 " nb_sectors=%d\n [ ", sector_num
, nb_sectors
);
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
;
43 for (sec
= sector_num
; sec
< end
; sec
++) {
44 QDEBUG ("sec%" PRId64
" ", sec
);
50 static void TRACE_STORE_IN_FVD (const char *str
, int64_t sector_num
,
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
;
57 for (sec
= sector_num
; sec
< end
; sec
++) {
58 QDEBUG ("sec%" PRId64
" ", sec
);
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)
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
)
109 to
->uuid
= from
->uuid
;
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
;
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
);
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
;
175 t
->alloc_tracer
*= -1; /* Guard against double free. */
179 static void dump_alloc_tracers (void)
183 for (i
= 1; i
< alloc_tracer_used
; i
++) {
184 if (!alloc_tracers
[i
]) {
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
,
198 t
->magic
== FVD_ALLOC_MAGIC
? "correct" : "wrong");
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
);
217 static inline void *_my_qemu_aio_get (AIOCBInfo
*pool
, BlockDriverState
*bs
,
218 BlockDriverCompletionFunc
* cb
,
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
;
228 #ifdef DEBUG_MEMORY_LEAK
229 trace_alloc (&acb
->tracer
, -1);
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
242 trace_free (&acb
->tracer
);
248 static inline void *_my_qemu_malloc (size_t size
)
251 pending_qemu_malloc
++;
252 #ifndef DEBUG_MEMORY_LEAK
253 return g_malloc(size
);
256 size
+= 1024; /* 512 bytes header and 512 bytes footer. */
257 uint8_t *ret
= g_malloc(size
);
258 trace_alloc (ret
, size
);
263 static inline void *_my_qemu_mallocz (size_t size
)
266 pending_qemu_malloc
++;
267 #ifndef DEBUG_MEMORY_LEAK
268 return g_malloc0(size
);
271 size
+= 1024; /* 512 bytes header and 512 bytes footer. */
272 uint8_t *ret
= g_malloc0(size
);
273 trace_alloc (ret
, size
);
278 static inline void *_my_qemu_blockalign (BlockDriverState
* bs
, size_t size
)
281 pending_qemu_malloc
++;
283 #ifndef DEBUG_MEMORY_LEAK
284 return qemu_blockalign (bs
, size
);
287 size
+= 1024; /* 512 bytes header and 512 bytes footer. */
288 uint8_t *ret
= qemu_blockalign (bs
, size
);
289 trace_alloc (ret
, size
);
294 static inline void _my_qemu_free (void *ptr
)
296 pending_qemu_malloc
--;
297 ASSERT (pending_qemu_malloc
>= 0);
298 #ifndef DEBUG_MEMORY_LEAK
302 uint8_t *q
= ((uint8_t *) ptr
) - 512;
308 static inline void _my_qemu_vfree (void *ptr
)
310 pending_qemu_malloc
--;
311 ASSERT (pending_qemu_malloc
>= 0);
312 #ifndef DEBUG_MEMORY_LEAK
316 uint8_t *q
= ((uint8_t *) ptr
) - 512;
322 static void count_pending_requests (BDRVFvdState
* s
)
327 QLIST_FOREACH (w
, &s
->copy_locks
, copy_lock
.next
) {
329 QDEBUG ("copy_lock: acb%llu-%p\n", w
->uuid
, w
);
332 QLIST_FOREACH (w
, &s
->write_locks
, write
.next_write_lock
) {
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 ();
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
)
362 /* Is it FvdAIOCB? */
363 if (acb
->magic
!= FVDAIOCB_MAGIC
|| acb
->common
.bs
->drv
!= &bdrv_fvd
) {
364 /* Is it CompactChildCB? */
365 CompactChildCB
*child
= p
;
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
)) {
375 if (acb
->uuid
== 20ULL) {
376 QPAUSE ("Processing the right acb");
381 void init_fvd_debug_fp (void)
384 sprintf (buf
, "/tmp/fvd.log-%d", getpid ());
385 if ((__fvd_debug_fp
= fopen (buf
, "wt")) == NULL
) {
386 __fvd_debug_fp
= stdout
;
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
;