patch-1.3.74 linux/mm/page_alloc.c
Next file: linux/mm/swap_state.c
Previous file: linux/mm/memory.c
Back to the patch index
Back to the overall index
- Lines: 255
- Date:
Wed Mar 13 18:55:52 1996
- Orig file:
v1.3.73/linux/mm/page_alloc.c
- Orig date:
Fri Jan 26 01:37:08 1996
diff -u --recursive --new-file v1.3.73/linux/mm/page_alloc.c linux/mm/page_alloc.c
@@ -23,17 +23,47 @@
#include <asm/bitops.h>
#include <asm/pgtable.h>
-static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
+int nr_swap_pages = 0;
+int nr_free_pages = 0;
+
+/*
+ * Free area management
+ *
+ * The free_area_list arrays point to the queue heads of the free areas
+ * of different sizes
+ */
+
+#define NR_MEM_LISTS 6
+
+struct free_area_struct {
+ struct page list;
+ unsigned int * map;
+};
+
+static struct free_area_struct free_area[NR_MEM_LISTS];
+
+static inline void init_mem_queue(struct page * head)
{
+ head->next = head;
+ head->prev = head;
+}
+
+static inline void add_mem_queue(struct page * head, struct page * entry)
+{
+ struct page * next = head->next;
+
entry->prev = head;
- (entry->next = head->next)->prev = entry;
+ entry->next = next;
+ next->prev = entry;
head->next = entry;
}
-static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
+static inline void remove_mem_queue(struct page * head, struct page * entry)
{
- struct mem_list * next = entry->next;
- (next->prev = entry->prev)->next = next;
+ struct page * next = entry->next;
+ struct page * prev = entry->prev;
+ next->prev = prev;
+ prev->next = next;
}
/*
@@ -55,30 +85,33 @@
/*
* Buddy system. Hairy. You really aren't expected to understand this
*/
-static inline void free_pages_ok(unsigned long addr, unsigned long order)
+static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
{
- unsigned long index = MAP_NR(addr) >> (1 + order);
- unsigned long mask = PAGE_MASK << order;
+ unsigned long index = map_nr >> (1 + order);
+ unsigned long mask = (~0UL) << order;
+
+#define list(x) (mem_map+(x))
- addr &= mask;
+ map_nr &= mask;
nr_free_pages += 1 << order;
while (order < NR_MEM_LISTS-1) {
- if (!change_bit(index, free_area_map[order]))
+ if (!change_bit(index, free_area[order].map))
break;
- remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
+ remove_mem_queue(&free_area[order].list, list(map_nr ^ (1+~mask)));
+ mask <<= 1;
order++;
index >>= 1;
- mask <<= 1;
- addr &= mask;
+ map_nr &= mask;
}
- add_mem_queue(free_area_list+order, (struct mem_list *) addr);
+ add_mem_queue(&free_area[order].list, list(map_nr));
+#undef list
}
-static inline void check_free_buffers(unsigned long addr)
+static inline void check_free_buffers(mem_map_t * map)
{
struct buffer_head * bh;
- bh = buffer_pages[MAP_NR(addr)];
+ bh = map->buffers;
if (bh) {
struct buffer_head *tmp = bh;
do {
@@ -92,21 +125,23 @@
void free_pages(unsigned long addr, unsigned long order)
{
- if (MAP_NR(addr) < MAP_NR(high_memory)) {
- unsigned long flag;
- mem_map_t * map = mem_map + MAP_NR(addr);
+ unsigned long map_nr = MAP_NR(addr);
+
+ if (map_nr < MAP_NR(high_memory)) {
+ mem_map_t * map = mem_map + map_nr;
if (map->reserved)
return;
if (map->count) {
+ unsigned long flag;
save_flags(flag);
cli();
if (!--map->count) {
- free_pages_ok(addr, order);
- delete_from_swap_cache(addr);
+ free_pages_ok(map_nr, order);
+ delete_from_swap_cache(map_nr);
}
restore_flags(flag);
if (map->count == 1)
- check_free_buffers(addr);
+ check_free_buffers(map);
return;
}
printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
@@ -118,43 +153,44 @@
/*
* Some ugly macros to speed up __get_free_pages()..
*/
-#define RMQUEUE(order, limit) \
-do { struct mem_list * queue = free_area_list+order; \
+#define MARK_USED(index, order, area) \
+ change_bit((index) >> (1+(order)), (area)->map)
+#define CAN_DMA(x) ((x)->dma)
+#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
+#define RMQUEUE(order, dma) \
+do { struct free_area_struct * area = free_area+order; \
unsigned long new_order = order; \
- do { struct mem_list *prev = queue, *ret; \
- while (queue != (ret = prev->next)) { \
- if ((unsigned long) ret < (limit)) { \
+ do { struct page *prev = &area->list, *ret; \
+ while (&area->list != (ret = prev->next)) { \
+ if (!dma || CAN_DMA(ret)) { \
+ unsigned long map_nr = ret - mem_map; \
(prev->next = ret->next)->prev = prev; \
- mark_used((unsigned long) ret, new_order); \
+ MARK_USED(map_nr, new_order, area); \
nr_free_pages -= 1 << order; \
+ EXPAND(ret, map_nr, order, new_order, area); \
restore_flags(flags); \
- EXPAND(ret, order, new_order); \
- return (unsigned long) ret; \
+ return ADDRESS(map_nr); \
} \
prev = ret; \
} \
- new_order++; queue++; \
+ new_order++; area++; \
} while (new_order < NR_MEM_LISTS); \
} while (0)
-static inline int mark_used(unsigned long addr, unsigned long order)
-{
- return change_bit(MAP_NR(addr) >> (1+order), free_area_map[order]);
-}
-
-#define EXPAND(addr,low,high) \
-do { unsigned long size = PAGE_SIZE << high; \
+#define EXPAND(map,index,low,high,area) \
+do { unsigned long size = 1 << high; \
while (high > low) { \
- high--; size >>= 1; cli(); \
- add_mem_queue(free_area_list+high, addr); \
- mark_used((unsigned long) addr, high); \
- restore_flags(flags); \
- addr = (struct mem_list *) (size + (unsigned long) addr); \
- } mem_map[MAP_NR((unsigned long) addr)].count = 1; \
- mem_map[MAP_NR((unsigned long) addr)].age = PAGE_INITIAL_AGE; \
+ area--; high--; size >>= 1; \
+ add_mem_queue(&area->list, map); \
+ MARK_USED(index, high, area); \
+ index += size; \
+ map += size; \
+ } \
+ map->count = 1; \
+ map->age = PAGE_INITIAL_AGE; \
} while (0)
-unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
+unsigned long __get_free_pages(int priority, unsigned long order, int dma)
{
unsigned long flags;
int reserved_pages;
@@ -176,12 +212,12 @@
repeat:
cli();
if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
- RMQUEUE(order, limit);
+ RMQUEUE(order, dma);
restore_flags(flags);
return 0;
}
restore_flags(flags);
- if (priority != GFP_BUFFER && try_to_free_page(priority, limit, 1))
+ if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
goto repeat;
return 0;
}
@@ -200,9 +236,9 @@
save_flags(flags);
cli();
for (order=0 ; order < NR_MEM_LISTS; order++) {
- struct mem_list * tmp;
+ struct page * tmp;
unsigned long nr = 0;
- for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
+ for (tmp = free_area[order].list.next ; tmp != &free_area[order].list ; tmp = tmp->next) {
nr ++;
}
total += nr * ((PAGE_SIZE>>10) << order);
@@ -246,18 +282,19 @@
memset(mem_map, 0, start_mem - (unsigned long) mem_map);
do {
--p;
+ p->dma = 1;
p->reserved = 1;
} while (p > mem_map);
for (i = 0 ; i < NR_MEM_LISTS ; i++) {
unsigned long bitmap_size;
- free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
+ init_mem_queue(&free_area[i].list);
mask += mask;
end_mem = (end_mem + ~mask) & mask;
bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
bitmap_size = (bitmap_size + 7) >> 3;
bitmap_size = LONG_ALIGN(bitmap_size);
- free_area_map[i] = (unsigned int *) start_mem;
+ free_area[i].map = (unsigned int *) start_mem;
memset((void *) start_mem, 0, bitmap_size);
start_mem += bitmap_size;
}
@@ -293,7 +330,7 @@
}
vma->vm_mm->rss++;
tsk->maj_flt++;
- if (!write_access && add_to_swap_cache(page, entry)) {
+ if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
set_pte(page_table, mk_pte(page, vma->vm_page_prot));
return;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this