
On 01.01.2017 17:11, Roman Bogorodskiy wrote:
Michal Privoznik wrote:
Since the internal implementation relies on a json parser being available, it make no sense to run this test if there's none available.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/Makefile.am | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
Not directly related to this patch (which looks OK to me BTW), I still cannot run virmacmaptest on FreeBSD: it segfaults on testMACRemove with a backtrace like this:
* thread #1: tid = 100493, 0x0000000803949401 libc.so.7`__je_arena_salloc(tsdn=0x000000080062ea88, ptr=0x5a5a5a5a5a5a5a5a, demote=false) + 97 at arena.h:1384, stop reason = signal SIGBUS: hardware error frame #0: 0x0000000803949401 libc.so.7`__je_arena_salloc(tsdn=0x000000080062ea88, ptr=0x5a5a5a5a5a5a5a5a, demote=false) + 97 at arena.h:1384 1381 /* Return the size of the allocation pointed to by ptr. */ 1382 JEMALLOC_ALWAYS_INLINE size_t 1383 arena_salloc(tsdn_t *tsdn, const void *ptr, bool demote) -> 1384 { 1385 size_t ret; 1386 arena_chunk_t *chunk; 1387 size_t pageind; (lldb) bt * thread #1: tid = 100493, 0x0000000803949401 libc.so.7`__je_arena_salloc(tsdn=0x000000080062ea88, ptr=0x5a5a5a5a5a5a5a5a, demote=false) + 97 at arena.h:1384, stop reason = signal SIGBUS: hardware error * frame #0: 0x0000000803949401 libc.so.7`__je_arena_salloc(tsdn=0x000000080062ea88, ptr=0x5a5a5a5a5a5a5a5a, demote=false) + 97 at arena.h:1384 frame #1: 0x00000008039557cb libc.so.7`ifree [inlined] __je_isalloc(tsdn=<unavailable>, ptr=0x5a5a5a5a5a5a5a5a, demote=false) + 13 at jemalloc_internal.h:1045 frame #2: 0x00000008039557be libc.so.7`ifree(tsd=0x000000080062ea88, ptr=0x5a5a5a5a5a5a5a5a, tcache=0x000000080720d000, slow_path=true) + 78 at jemalloc_jemalloc.c:1870 frame #3: 0x00000008039558f0 libc.so.7`__free(ptr=0x5a5a5a5a5a5a5a5a) + 112 at jemalloc_jemalloc.c:1997 frame #4: 0x0000000800c71672 libvirt.so.0`virFree(ptrptr=0x000000080721cf80) + 34 at viralloc.c:582 frame #5: 0x0000000800ce5a60 libvirt.so.0`virStringListFree(strings=0x000000080721cf80) + 80 at virstring.c:251 frame #6: 0x0000000800cb973c libvirt.so.0`virMacMapHashFree(payload=0x000000080721cf80, name=0x000000080723f268) + 28 at virmacmap.c:67 frame #7: 0x0000000800ca0179 libvirt.so.0`virHashAddOrUpdateEntry(table=0x000000080721d420, name=0x00000000004071c0, userdata=0x000000080721cf80, is_update=true) + 297 at virhash.c:352 frame #8: 0x0000000800ca032a libvirt.so.0`virHashUpdateEntry(table=0x000000080721d420, name=0x00000000004071c0, userdata=0x000000080721cf80) + 42 at virhash.c:415 frame #9: 0x0000000800cb9c8f libvirt.so.0`virMacMapRemoveLocked(mgr=0x000000080721cc80, domain="f24", mac="aa:bb:cc:dd:ee:ff") + 175 at virmacmap.c:129 frame #10: 0x0000000800cb9bc1 libvirt.so.0`virMacMapRemove(mgr=0x000000080721cc80, domain="f24", mac="aa:bb:cc:dd:ee:ff") + 49 at virmacmap.c:346 frame #11: 0x00000000004040a0 virmacmaptest`testMACRemove(opaque=0x00007fffffffe260) + 288 at virmacmaptest.c:109 frame #12: 0x00000000004043ac virmacmaptest`virTestRun(title="Remove \"f24\" in \"simple2\"", body=(virmacmaptest`testMACRemove at virmacmaptest.c:91), data=0x00007fffffffe260) + 284 at testutils.c:180 frame #13: 0x0000000000403074 virmacmaptest`mymain + 468 at virmacmaptest.c:207 frame #14: 0x000000000040629d virmacmaptest`virTestMain(argc=1, argv=0x00007fffffffe610, func=(virmacmaptest`mymain at virmacmaptest.c:158)) + 2189 at testutils.c:992 frame #15: 0x0000000000402e8d virmacmaptest`main(argc=1, argv=0x00007fffffffe610) + 61 at virmacmaptest.c:239 frame #16: 0x0000000000402d4f virmacmaptest`_start + 383 (lldb)
It looks like a problem in virMacMapRemoveLocked() to me, because it calls virStringListRemove() on the existing macs list which modifies a pointer to the macs string list. Later, when updating a hash table entry for the existing domain, it tries to clean up the old data by calling virStringListFree (via virMacMapHashFree) on the wrong pointer. I'm not sure why it doesn't show up on Linux though, maybe my analysis is wrong.
Ah. Running the test under valgrind shows the same problem except the process is not getting SIGSEGV. The problem is indeed in virMacMapRemoveLocked(). But it is slightly more complicated. If a MAC address that caller wants to remove is in the list, virStringListRemove() is called which modifies the string list. Then either virHashSteal() or virHashUpdateEntry() is called to update the pointer to the list in the hash table. However, virHashUpdateEntry() calls the dataFree callback - but over pointer to the old list. Looks to me the best would be to not set dataFree callback at all. I'm testing this approach now. Will post the patches shortly.
I was able to fix this with a change like this:
diff --git a/src/util/virmacmap.c b/src/util/virmacmap.c index 36c364e10..b328ba714 100644 --- a/src/util/virmacmap.c +++ b/src/util/virmacmap.c @@ -116,21 +116,31 @@ virMacMapRemoveLocked(virMacMapPtr mgr, { char **macsList = NULL; char **newMacsList = NULL; + int i = 0, ret = -1;
if (!(macsList = virHashLookup(mgr->macs, domain))) return 0;
- newMacsList = macsList; - virStringListRemove(&macsList, mac); - if (!macsList) { + for (i = 0; macsList && macsList[i]; i++) { + if (!STREQ(macsList[i], mac)) + newMacsList = virStringListAdd((const char **)newMacsList, + macsList[i]); + } + + if (!newMacsList) { virHashSteal(mgr->macs, domain); } else { if (macsList != newMacsList && virHashUpdateEntry(mgr->macs, domain, newMacsList) < 0) - return -1; + goto cleanup; }
- return 0; + newMacsList = NULL; + ret = 0; + + cleanup: + virStringListFree(newMacsList); + return ret;
Yeah, I had it this way originally, but some people on the list disliked the idea of allocating more memory on an element remove. Michal