Messages in this thread Patch in this message | | | Date | Wed, 14 Jul 2004 23:03:51 +0900 (JST) | Subject | [PATCH] memory hotremoval for linux-2.6.7 [5/16] | From | Hirokazu Takahashi <> |
| |
$Id: va-proc_memhotplug.patch,v 1.14 2004/07/06 09:05:54 taka Exp $
diff -dpur linux-2.6.7/mm/page_alloc.c linux-2.6.7-mh/mm/page_alloc.c --- linux-2.6.7/mm/page_alloc.c.orig 2004-06-17 16:28:03.000000000 +0900 +++ linux-2.6.7-mh/mm/page_alloc.c 2004-06-17 16:28:34.000000000 +0900 @@ -32,6 +32,7 @@ #include <linux/topology.h> #include <linux/sysctl.h> #include <linux/cpu.h> +#include <linux/proc_fs.h> #include <asm/tlbflush.h> @@ -2120,3 +2121,244 @@ int lower_zone_protection_sysctl_handler setup_per_zone_protection(); return 0; } + +#ifdef CONFIG_MEMHOTPLUG +static int mhtest_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *p; + int i, j, len; + const struct pglist_data *pgdat; + const struct zone *z; + + p = page; + for(i = 0; i < numnodes; i++) { + pgdat = NODE_DATA(i); + if (pgdat == NULL) + continue; + len = sprintf(p, "Node %d %sabled %shotremovable\n", i, + pgdat->enabled ? "en" : "dis", + pgdat->removable ? "" : "non"); + p += len; + for (j = 0; j < MAX_NR_ZONES; j++) { + z = &pgdat->node_zones[j]; + if (! z->present_pages) + /* skip empty zone */ + continue; + len = sprintf(p, + "\t%s[%d]: free %ld, active %ld, present %ld\n", + z->name, NODEZONE(i, j), + z->free_pages, z->nr_active, z->present_pages); + p += len; + } + *p++ = '\n'; + } + len = p - page; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len < 0) + len = 0; + if (len > count) + len = count; + + return len; +} + +static void mhtest_enable(int); +static void mhtest_disable(int); +static void mhtest_plug(int); +static void mhtest_unplug(int); +static void mhtest_purge(int); +static void mhtest_remap(int); +static void mhtest_active(int); +static void mhtest_inuse(int); + +const static struct { + char *cmd; + void (*func)(int); + char zone_check; +} mhtest_cmds[] = { + { "disable", mhtest_disable, 0 }, + { "enable", mhtest_enable, 0 }, + { "plug", mhtest_plug, 0 }, + { "unplug", mhtest_unplug, 0 }, + { "purge", mhtest_purge, 1 }, + { "remap", mhtest_remap, 1 }, + { "active", mhtest_active, 1 }, + { "inuse", mhtest_inuse, 1 }, + { NULL, NULL }}; + +static void +mhtest_disable(int idx) { + int i, z; + + printk("disable %d\n", idx); + /* XXX */ + for (z = 0; z < MAX_NR_ZONES; z++) { + for (i = 0; i < NR_CPUS; i++) { + struct per_cpu_pages *pcp; + + pcp = &zone_table[NODEZONE(idx, z)]->pageset[i].pcp[0]; /* hot */ + pcp->low = pcp->high = 0; + + pcp = &zone_table[NODEZONE(idx, z)]->pageset[i].pcp[1]; /* cold */ + pcp->low = pcp->high = 0; + } + zone_table[NODEZONE(idx, z)]->pages_high = + zone_table[NODEZONE(idx, z)]->present_pages; + } + disable_node(idx); +} +static void +mhtest_enable(int idx) { + int i, z; + + printk("enable %d\n", idx); + for (z = 0; z < MAX_NR_ZONES; z++) { + zone_table[NODEZONE(idx, z)]->pages_high = + zone_table[NODEZONE(idx, z)]->pages_min * 3; + /* XXX */ + for (i = 0; i < NR_CPUS; i++) { + struct per_cpu_pages *pcp; + + pcp = &zone_table[NODEZONE(idx, z)]->pageset[i].pcp[0]; /* hot */ + pcp->low = 2 * pcp->batch; + pcp->high = 6 * pcp->batch; + + pcp = &zone_table[NODEZONE(idx, z)]->pageset[i].pcp[1]; /* cold */ + pcp->high = 2 * pcp->batch; + } + } + enable_node(idx); +} + +static void +mhtest_plug(int idx) { + + if (NODE_DATA(idx) != NULL) { + printk("Already plugged\n"); + return; + } + plug_node(idx); +} + +static void +mhtest_unplug(int idx) { + + unplug_node(idx); +} + +static void +mhtest_purge(int idx) +{ + printk("purge %d\n", idx); + wake_up_interruptible(&zone_table[idx]->zone_pgdat->kswapd_wait); + /* XXX overkill, but who cares? */ + on_each_cpu(drain_local_pages, NULL, 1, 1); +} + +static void +mhtest_remap(int idx) { + + on_each_cpu(drain_local_pages, NULL, 1, 1); + kernel_thread(mmigrated, zone_table[idx], CLONE_KERNEL); +} + +static void +mhtest_active(int idx) +{ + struct list_head *l; + int i; + + if (zone_table[idx] == NULL) + return; + spin_lock_irq(&zone_table[idx]->lru_lock); + i = 0; + list_for_each(l, &zone_table[idx]->active_list) { + printk(" %lx", (unsigned long)list_entry(l, struct page, lru)); + i++; + if (i == 10) + break; + } + spin_unlock_irq(&zone_table[idx]->lru_lock); + printk("\n"); +} + +static void +mhtest_inuse(int idx) +{ + int i; + + if (zone_table[idx] == NULL) + return; + for(i = 0; i < zone_table[idx]->spanned_pages; i++) + if (page_count(&zone_table[idx]->zone_mem_map[i])) + printk(" %p", &zone_table[idx]->zone_mem_map[i]); + printk("\n"); +} + +static int mhtest_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int idx; + char buf[64], *p; + int i; + + if (count > sizeof(buf) - 1) + count = sizeof(buf) - 1; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + buf[count] = 0; + + p = strchr(buf, ' '); + if (p == NULL) + goto out; + + *p++ = '\0'; + idx = (int)simple_strtoul(p, NULL, 0); + + if (idx > MAX_NR_ZONES*MAX_NUMNODES) { + printk("Argument out of range\n"); + goto out; + } + + for(i = 0; ; i++) { + if (mhtest_cmds[i].cmd == NULL) + break; + if (strcmp(buf, mhtest_cmds[i].cmd) == 0) { + if (mhtest_cmds[i].zone_check) { + if (zone_table[idx] == NULL) { + printk("Zone %d not plugged\n", idx); + return count; + } + } else if (strcmp(buf, "plug") != 0 && + NODE_DATA(idx) == NULL) { + printk("Node %d not plugged\n", idx); + return count; + } + (mhtest_cmds[i].func)(idx); + break; + } + } +out: + return count; +} + +static int __init procmhtest_init(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry("memhotplug", 0, NULL); + if (entry == NULL) + return -1; + + entry->read_proc = &mhtest_read; + entry->write_proc = &mhtest_write; + return 0; +} +__initcall(procmhtest_init); +#endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |