summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-17 23:04:54 -0700
committerGary King <gking@nvidia.com>2010-05-17 23:08:31 -0700
commit94af0b4ea79b5b633632c342fd7011b7c8cd88fd (patch)
treef1bf6e4a40bc262622b125caa194bca4fa7458b4 /drivers
parent90c2e642c9ab27dfffe141d9f8f4840cef1c5a89 (diff)
[nvmap] restructure allocations to avoid allocation inside spinlocks
statically allocate a maximally-sized block array at heap init time, rather than dynamically doubling the array size when spare blocks are unavailable. allocate new handle ref objects prior to locking the file's ref lock Change-Id: I193210e059ed38c67287650fc4b578e85097ec12
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/nvmap.c43
1 files changed, 9 insertions, 34 deletions
diff --git a/drivers/char/nvmap.c b/drivers/char/nvmap.c
index e58f18fee955..f85dfc2bf7ef 100644
--- a/drivers/char/nvmap.c
+++ b/drivers/char/nvmap.c
@@ -20,6 +20,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#define NV_DEBUG 0
+
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/bitmap.h>
@@ -262,17 +264,18 @@ static unsigned long _nvmap_carveout_blockstat(struct nvmap_carveout *co,
static int _nvmap_init_carveout(struct nvmap_carveout *co,
const char *name, unsigned long base_address, size_t len)
{
- const unsigned int min_blocks = 16;
+ unsigned int num_blocks;
struct nvmap_mem_block *blocks = NULL;
int i;
- blocks = kzalloc(sizeof(*blocks)*min_blocks, GFP_KERNEL);
+ num_blocks = min_t(unsigned int, len/1024, 1024);
+ blocks = vmalloc(sizeof(*blocks)*num_blocks);
if (!blocks) goto fail;
co->name = kstrdup(name, GFP_KERNEL);
if (!co->name) goto fail;
- for (i=1; i<min_blocks; i++) {
+ for (i=1; i<num_blocks; i++) {
blocks[i].next = i+1;
blocks[i].prev = i-1;
blocks[i].next_free = -1;
@@ -286,7 +289,7 @@ static int _nvmap_init_carveout(struct nvmap_carveout *co,
blocks[0].base = base_address;
blocks[0].size = len;
co->blocks = blocks;
- co->num_blocks = min_blocks;
+ co->num_blocks = num_blocks;
spin_lock_init(&co->lock);
co->block_index = 0;
co->spare_index = 1;
@@ -298,39 +301,12 @@ fail:
return -ENOMEM;
}
-static int nvmap_grow_blocks(struct nvmap_carveout *co)
-{
- struct nvmap_mem_block *blocks;
- unsigned int i;
-
- if (co->num_blocks >= 1<<(8*sizeof(co->free_index)-1)) return -ENOMEM;
- blocks = kzalloc(sizeof(*blocks)*(co->num_blocks*2), GFP_KERNEL);
- if (!blocks) return -ENOMEM;
-
- memcpy(blocks, co->blocks, sizeof(*blocks)*(co->num_blocks));
- kfree(co->blocks);
- co->blocks = blocks;
- for (i=co->num_blocks; i<co->num_blocks*2; i++) {
- blocks[i].next = i+1;
- blocks[i].prev = i-1;
- blocks[i].next_free = -1;
- blocks[i].prev_free = -1;
- }
- blocks[co->num_blocks].prev = -1;
- blocks[i-1].next = -1;
- co->spare_index = co->num_blocks;
- co->num_blocks *= 2;
- return 0;
-}
-
static int nvmap_get_spare(struct nvmap_carveout *co) {
int idx;
if (co->spare_index == -1)
- if (nvmap_grow_blocks(co))
- return -1;
+ return -1;
- BUG_ON(co->spare_index == -1);
idx = co->spare_index;
co->spare_index = co->blocks[idx].next;
co->blocks[idx].next = -1;
@@ -2039,10 +2015,8 @@ static int _nvmap_do_create(struct nvmap_file_priv *priv,
BUG_ON(!h);
- spin_lock(&priv->ref_lock);
r = kzalloc(sizeof(*r), GFP_KERNEL);
if (!r) {
- spin_unlock(&priv->ref_lock);
if (h) _nvmap_handle_put(h);
return -ENOMEM;
}
@@ -2051,6 +2025,7 @@ static int _nvmap_do_create(struct nvmap_file_priv *priv,
r->h = h;
atomic_set(&r->pin, 0);
+ spin_lock(&priv->ref_lock);
p = &priv->handle_refs.rb_node;
while (*p) {
struct nvmap_handle_ref *l;