diff -urNp 2.4.19rc3aa1/fs/proc/proc_misc.c buddy/fs/proc/proc_misc.c --- 2.4.19rc3aa1/fs/proc/proc_misc.c Mon Jul 22 18:49:13 2002 +++ buddy/fs/proc/proc_misc.c Mon Jul 22 18:50:28 2002 @@ -234,6 +234,20 @@ static int meminfo_read_proc(char *page, #undef K } +extern struct seq_operations fragmentation_op; +static int fragmentation_open(struct inode *inode, struct file *file) +{ + (void)inode; + return seq_open(file, &fragmentation_op); +} + +static struct file_operations fragmentation_file_operations = { + open: fragmentation_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; + static int version_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -676,6 +690,7 @@ void __init proc_misc_init(void) entry->proc_fops = &proc_kmsg_operations; create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); + create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); #ifdef CONFIG_MODULES create_seq_entry("ksyms", 0, &proc_ksyms_operations); #endif diff -urNp 2.4.19rc3aa1/mm/page_alloc.c buddy/mm/page_alloc.c --- 2.4.19rc3aa1/mm/page_alloc.c Mon Jul 22 18:49:13 2002 +++ buddy/mm/page_alloc.c Mon Jul 22 18:50:28 2002 @@ -1027,3 +1027,71 @@ static int __init setup_lower_zone_reser } __setup("lower_zone_reserve=", setup_lower_zone_reserve); + +#ifdef CONFIG_PROC_FS + +#include + +static void *frag_start(struct seq_file *m, loff_t *pos) +{ + pg_data_t *pgdat; + loff_t node = *pos; + + (void)m; + + for (pgdat = pgdat_list; pgdat && node; pgdat = pgdat->node_next) + --node; + + return pgdat; +} + +static void *frag_next(struct seq_file *m, void *arg, loff_t *pos) +{ + pg_data_t *pgdat = (pg_data_t *)arg; + + (void)m; + (*pos)++; + return pgdat->node_next; +} + +static void frag_stop(struct seq_file *m, void *arg) +{ + (void)m; + (void)arg; +} + +/* + * This walks the freelist for each zone. Whilst this is slow, I'd rather + * be slow here than slow down the fast path by keeping stats - mjbligh + */ +static int frag_show(struct seq_file *m, void *arg) +{ + pg_data_t *pgdat = (pg_data_t *)arg; + zone_t *zone, *node_zones = pgdat->node_zones; + unsigned long flags; + int order; + + for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { + spin_lock_irqsave(&zone->lock, flags); + seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); + for (order = 0; order < MAX_ORDER; ++order) { + unsigned long nr_bufs = 0; + list_t *elem; + list_for_each(elem, &zone->free_area[order].free_list) + ++nr_bufs; + seq_printf(m, "%6lu ", nr_bufs); + } + spin_unlock_irqrestore(&zone->lock, flags); + seq_putc(m, '\n'); + } + return 0; +} + +struct seq_operations fragmentation_op = { + start: frag_start, + next: frag_next, + stop: frag_stop, + show: frag_show, +}; + +#endif /* CONFIG_PROC_FS */