Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 137080
b: refs/heads/master
c: 9f7dcf2
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo committed Mar 6, 2009
1 parent 35d7f6c commit b695003
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 49 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1880d93b80acc3171850e9df5048bcb26b75c2f5
refs/heads/master: 9f7dcf224bd09ec9ebcbfb383bf2c465e0e0b03d
108 changes: 60 additions & 48 deletions trunk/mm/percpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,50 @@ static void pcpu_chunk_addr_insert(struct pcpu_chunk *new)
rb_insert_color(&new->rb_node, &pcpu_addr_root);
}

/**
* pcpu_extend_area_map - extend area map for allocation
* @chunk: target chunk
*
* Extend area map of @chunk so that it can accomodate an allocation.
* A single allocation can split an area into three areas, so this
* function makes sure that @chunk->map has at least two extra slots.
*
* RETURNS:
* 0 if noop, 1 if successfully extended, -errno on failure.
*/
static int pcpu_extend_area_map(struct pcpu_chunk *chunk)
{
int new_alloc;
int *new;
size_t size;

/* has enough? */
if (chunk->map_alloc >= chunk->map_used + 2)
return 0;

new_alloc = PCPU_DFL_MAP_ALLOC;
while (new_alloc < chunk->map_used + 2)
new_alloc *= 2;

new = pcpu_mem_alloc(new_alloc * sizeof(new[0]));
if (!new)
return -ENOMEM;

size = chunk->map_alloc * sizeof(chunk->map[0]);
memcpy(new, chunk->map, size);

/*
* map_alloc < PCPU_DFL_MAP_ALLOC indicates that the chunk is
* one of the first chunks and still using static map.
*/
if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
pcpu_mem_free(chunk->map, size);

chunk->map_alloc = new_alloc;
chunk->map = new;
return 0;
}

/**
* pcpu_split_block - split a map block
* @chunk: chunk of interest
Expand All @@ -321,44 +365,16 @@ static void pcpu_chunk_addr_insert(struct pcpu_chunk *new)
* depending on @head, is reduced by @tail bytes and @tail byte block
* is inserted after the target block.
*
* RETURNS:
* 0 on success, -errno on failure.
* @chunk->map must have enough free slots to accomodate the split.
*/
static int pcpu_split_block(struct pcpu_chunk *chunk, int i, int head, int tail)
static void pcpu_split_block(struct pcpu_chunk *chunk, int i,
int head, int tail)
{
int nr_extra = !!head + !!tail;
int target = chunk->map_used + nr_extra;

/* reallocation required? */
if (chunk->map_alloc < target) {
int new_alloc;
int *new;
size_t size;

new_alloc = PCPU_DFL_MAP_ALLOC;
while (new_alloc < target)
new_alloc *= 2;

new = pcpu_mem_alloc(new_alloc * sizeof(new[0]));
if (!new)
return -ENOMEM;

size = chunk->map_alloc * sizeof(chunk->map[0]);
memcpy(new, chunk->map, size);

/*
* map_alloc < PCPU_DFL_MAP_ALLOC indicates that the
* chunk is one of the first chunks and still using
* static map.
*/
if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
pcpu_mem_free(chunk->map, size);

chunk->map_alloc = new_alloc;
chunk->map = new;
}
BUG_ON(chunk->map_alloc < chunk->map_used + nr_extra);

/* insert a new subblock */
/* insert new subblocks */
memmove(&chunk->map[i + nr_extra], &chunk->map[i],
sizeof(chunk->map[0]) * (chunk->map_used - i));
chunk->map_used += nr_extra;
Expand All @@ -371,7 +387,6 @@ static int pcpu_split_block(struct pcpu_chunk *chunk, int i, int head, int tail)
chunk->map[i++] -= tail;
chunk->map[i] = tail;
}
return 0;
}

/**
Expand All @@ -384,8 +399,11 @@ static int pcpu_split_block(struct pcpu_chunk *chunk, int i, int head, int tail)
* Note that this function only allocates the offset. It doesn't
* populate or map the area.
*
* @chunk->map must have at least two free slots.
*
* RETURNS:
* Allocated offset in @chunk on success, -errno on failure.
* Allocated offset in @chunk on success, -1 if no matching area is
* found.
*/
static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
{
Expand Down Expand Up @@ -433,8 +451,7 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)

/* split if warranted */
if (head || tail) {
if (pcpu_split_block(chunk, i, head, tail))
return -ENOMEM;
pcpu_split_block(chunk, i, head, tail);
if (head) {
i++;
off += head;
Expand All @@ -461,14 +478,8 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
chunk->contig_hint = max_contig; /* fully scanned */
pcpu_chunk_relocate(chunk, oslot);

/*
* Tell the upper layer that this chunk has no area left.
* Note that this is not an error condition but a notification
* to upper layer that it needs to look at other chunks.
* -ENOSPC is chosen as it isn't used in memory subsystem and
* matches the meaning in a way.
*/
return -ENOSPC;
/* tell the upper layer that this chunk has no matching area */
return -1;
}

/**
Expand Down Expand Up @@ -755,7 +766,8 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
/* serve reserved allocations from the reserved chunk if available */
if (reserved && pcpu_reserved_chunk) {
chunk = pcpu_reserved_chunk;
if (size > chunk->contig_hint)
if (size > chunk->contig_hint ||
pcpu_extend_area_map(chunk) < 0)
goto out_unlock;
off = pcpu_alloc_area(chunk, size, align);
if (off >= 0)
Expand All @@ -768,11 +780,11 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
if (size > chunk->contig_hint)
continue;
if (pcpu_extend_area_map(chunk) < 0)
goto out_unlock;
off = pcpu_alloc_area(chunk, size, align);
if (off >= 0)
goto area_found;
if (off != -ENOSPC)
goto out_unlock;
}
}

Expand Down

0 comments on commit b695003

Please sign in to comment.