diff options
author | Jim Keniston <jkenisto@us.ibm.com> | 2008-10-03 14:11:41 -0700 |
---|---|---|
committer | Jim Keniston <jkenisto@us.ibm.com> | 2008-10-03 14:11:41 -0700 |
commit | b678f438a390da7f9a6712a22c95d069dfd6643b (patch) | |
tree | 2bf12daf34f2f534af8add9c3aa93afd1abdf38b /runtime/addr-map.c | |
parent | de50692ab43992557f4e0b719e09c0a88127a603 (diff) | |
parent | 748eea887135ac44f5c4b0a7499225d4cb2cbefe (diff) | |
download | systemtap-steved-b678f438a390da7f9a6712a22c95d069dfd6643b.tar.gz systemtap-steved-b678f438a390da7f9a6712a22c95d069dfd6643b.tar.xz systemtap-steved-b678f438a390da7f9a6712a22c95d069dfd6643b.zip |
Merge branch 'master' of ssh://kenistoj@sources.redhat.com/git/systemtap
Diffstat (limited to 'runtime/addr-map.c')
-rw-r--r-- | runtime/addr-map.c | 100 |
1 files changed, 54 insertions, 46 deletions
diff --git a/runtime/addr-map.c b/runtime/addr-map.c index 8231b57f..706da454 100644 --- a/runtime/addr-map.c +++ b/runtime/addr-map.c @@ -113,64 +113,72 @@ add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, struct addr_map_entry* max_entry = 0; struct addr_map_entry* new_entry = 0; size_t existing = 0; - + + /* Loop allocating memory for a new entry in the map. */ while (1) { - size_t old_size; + size_t old_size = 0; spin_lock(&addr_map_lock); old_map = blackmap; - if (!blackmap) - { - existing = 0; - old_size = 0; - } - else + if (old_map) + old_size = old_map->size; + /* Either this is the first time through the loop, or we + allocated a map previous time, but someone has come in and + added an entry while we were sleeping. */ + if (!new_map || (new_map && new_map->size < old_size + 1)) { - min_entry = lookup_addr_aux(min_addr, blackmap); - max_entry = lookup_addr_aux(max_addr, blackmap); - if (min_entry || max_entry) + spin_unlock(&addr_map_lock); + if (new_map) { - if (existing_min) - *existing_min = min_entry; - if (existing_max) - *existing_max = max_entry; - spin_unlock(&addr_map_lock); - return 1; + kfree(new_map); + new_map = 0; } - existing = upper_bound(min_addr, old_map); - old_size = old_map->size; + new_map = kmalloc(sizeof(*new_map) + + sizeof(*new_entry) * (old_size + 1), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + new_map->size = old_size + 1; } - spin_unlock(&addr_map_lock); - new_map = kmalloc(sizeof(*new_map) - + sizeof(*new_entry) * (old_size + 1), - GFP_KERNEL); - if (!new_map) - return -ENOMEM; - spin_lock(&addr_map_lock); - if (blackmap != old_map) + else + break; + } + if (!blackmap) + { + existing = 0; + } + else + { + min_entry = lookup_addr_aux(min_addr, blackmap); + max_entry = lookup_addr_aux(max_addr, blackmap); + if (min_entry || max_entry) { - kfree(new_map); + if (existing_min) + *existing_min = min_entry; + if (existing_max) + *existing_max = max_entry; spin_unlock(&addr_map_lock); - continue; - } - new_entry = &new_map->entries[existing]; - new_entry->min = min_addr; - new_entry->max = max_addr; - if (old_map) - { - memcpy(&new_map->entries, old_map->entries, - existing * sizeof(*new_entry)); - if (old_map->size > existing) - memcpy(new_entry + 1, &old_map->entries[existing + 1], - (old_map->size - existing) * sizeof(*new_entry)); + kfree(new_map); + return 1; } - new_map->size = blackmap->size + 1; - blackmap = new_map; - spin_unlock(&addr_map_lock); - if (old_map) - kfree(old_map); - return 0; + existing = upper_bound(min_addr, old_map); + } + new_entry = &new_map->entries[existing]; + new_entry->min = min_addr; + new_entry->max = max_addr; + if (old_map) + { + memcpy(&new_map->entries, old_map->entries, + existing * sizeof(*new_entry)); + if (old_map->size > existing) + memcpy(new_entry + 1, &old_map->entries[existing], + (old_map->size - existing) * sizeof(*new_entry)); } + blackmap = new_map; + spin_unlock(&addr_map_lock); + if (old_map) + kfree(old_map); + return 0; } void |