summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Roell <troell@nvidia.com>2010-09-01 06:13:47 -0600
committerJanne Hellsten <jhellsten@nvidia.com>2010-09-02 06:22:41 -0700
commit3a7a9bcd117f8c0f09c6eb74e79b0996397bf486 (patch)
tree40799988f159ecbe17c2766ababdea66fb6902f9
parent652c4abaaa5e9dea1468610740e1761fea4f1517 (diff)
video: tegra: nvmap: disallow splitting when no spare blocks available
The block realignment if a block wasn't split lead to a slow leak of carveout memory if the previous block was not a free block. Change-Id: I08bd89364932f2c4fc4faf1dec177dab03e82a9a Reviewed-on: http://git-master/r/5851 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Thomas Roell <troell@nvidia.com>
-rw-r--r--drivers/video/tegra/nvmap.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/drivers/video/tegra/nvmap.c b/drivers/video/tegra/nvmap.c
index 448ac8f34771..521471b0d7ac 100644
--- a/drivers/video/tegra/nvmap.c
+++ b/drivers/video/tegra/nvmap.c
@@ -271,7 +271,7 @@ static int _nvmap_init_carveout(struct nvmap_carveout *co,
struct nvmap_mem_block *blocks = NULL;
int i;
- num_blocks = min_t(unsigned int, len/1024, 1024);
+ num_blocks = min_t(unsigned int, len/1024, 2048);
blocks = vmalloc(sizeof(*blocks)*num_blocks);
if (!blocks) goto fail;
@@ -338,7 +338,7 @@ static void nvmap_zap_free(struct nvmap_carveout *co, int idx)
block->next_free = -1;
}
-static void nvmap_split_block(struct nvmap_carveout *co,
+static int nvmap_split_block(struct nvmap_carveout *co,
int idx, size_t start, size_t size)
{
if (BLOCK(co, idx)->base < start) {
@@ -363,12 +363,9 @@ static void nvmap_split_block(struct nvmap_carveout *co,
co->blocks[co->free_index].prev_free = spare_idx;
co->free_index = spare_idx;
} else {
- if (block->prev != -1) {
- spare = BLOCK(co, block->prev);
- spare->size += start - block->base;
- block->size -= (start - block->base);
- block->base = start;
- }
+ /* not being able to split is fatal here, because we need
+ * to realign block->base */
+ return -ENOMEM;
}
}
@@ -394,6 +391,8 @@ static void nvmap_split_block(struct nvmap_carveout *co,
}
nvmap_zap_free(co, idx);
+
+ return 0;
}
#define next_spare next
@@ -482,16 +481,19 @@ static int nvmap_carveout_alloc(struct nvmap_carveout *co,
r_max = max_t(size_t, rjust - b->base, end - (rjust + size));
if (b->base + b->size >= ljust + size) {
- if (l_max >= r_max)
- nvmap_split_block(co, idx, ljust, size);
- else
- nvmap_split_block(co, idx, rjust, size);
- break;
+ if (l_max >= r_max) {
+ if (!nvmap_split_block(co, idx, ljust, size))
+ break;
+ } else {
+ if (!nvmap_split_block(co, idx, rjust, size))
+ break;
+ }
}
idx = b->next_free;
}
spin_unlock(&co->lock);
+
return idx;
}
@@ -2698,12 +2700,13 @@ static int _nvmap_try_create_preserved(struct nvmap_carveout *co,
struct nvmap_mem_block *b = BLOCK(co, idx);
unsigned long blk_end = b->base + b->size;
if (b->base <= base && blk_end >= end) {
- nvmap_split_block(co, idx, base, size);
- h->carveout.block_idx = idx;
- h->carveout.base = co->blocks[idx].base;
- h->carveout.co_heap = co;
- h->alloc = true;
- break;
+ if (!nvmap_split_block(co, idx, base, size)) {
+ h->carveout.block_idx = idx;
+ h->carveout.base = co->blocks[idx].base;
+ h->carveout.co_heap = co;
+ h->alloc = true;
+ break;
+ }
}
idx = b->next_free;
}