diff options
Diffstat (limited to 'drivers/base/node.c')
-rw-r--r-- | drivers/base/node.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/base/node.c b/drivers/base/node.c new file mode 100644 index 000000000000..583d57ec49a8 --- /dev/null +++ b/drivers/base/node.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * drivers/base/node.c - basic Node class support | ||
3 | */ | ||
4 | |||
5 | #include <linux/sysdev.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/mm.h> | ||
9 | #include <linux/node.h> | ||
10 | #include <linux/hugetlb.h> | ||
11 | #include <linux/cpumask.h> | ||
12 | #include <linux/topology.h> | ||
13 | #include <linux/nodemask.h> | ||
14 | |||
15 | static struct sysdev_class node_class = { | ||
16 | set_kset_name("node"), | ||
17 | }; | ||
18 | |||
19 | |||
20 | static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) | ||
21 | { | ||
22 | struct node *node_dev = to_node(dev); | ||
23 | cpumask_t mask = node_to_cpumask(node_dev->sysdev.id); | ||
24 | int len; | ||
25 | |||
26 | /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */ | ||
27 | BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2); | ||
28 | |||
29 | len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask); | ||
30 | len += sprintf(buf + len, "\n"); | ||
31 | return len; | ||
32 | } | ||
33 | |||
34 | static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL); | ||
35 | |||
36 | #define K(x) ((x) << (PAGE_SHIFT - 10)) | ||
37 | static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) | ||
38 | { | ||
39 | int n; | ||
40 | int nid = dev->id; | ||
41 | struct sysinfo i; | ||
42 | unsigned long inactive; | ||
43 | unsigned long active; | ||
44 | unsigned long free; | ||
45 | |||
46 | si_meminfo_node(&i, nid); | ||
47 | __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); | ||
48 | |||
49 | n = sprintf(buf, "\n" | ||
50 | "Node %d MemTotal: %8lu kB\n" | ||
51 | "Node %d MemFree: %8lu kB\n" | ||
52 | "Node %d MemUsed: %8lu kB\n" | ||
53 | "Node %d Active: %8lu kB\n" | ||
54 | "Node %d Inactive: %8lu kB\n" | ||
55 | "Node %d HighTotal: %8lu kB\n" | ||
56 | "Node %d HighFree: %8lu kB\n" | ||
57 | "Node %d LowTotal: %8lu kB\n" | ||
58 | "Node %d LowFree: %8lu kB\n", | ||
59 | nid, K(i.totalram), | ||
60 | nid, K(i.freeram), | ||
61 | nid, K(i.totalram - i.freeram), | ||
62 | nid, K(active), | ||
63 | nid, K(inactive), | ||
64 | nid, K(i.totalhigh), | ||
65 | nid, K(i.freehigh), | ||
66 | nid, K(i.totalram - i.totalhigh), | ||
67 | nid, K(i.freeram - i.freehigh)); | ||
68 | n += hugetlb_report_node_meminfo(nid, buf + n); | ||
69 | return n; | ||
70 | } | ||
71 | |||
72 | #undef K | ||
73 | static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); | ||
74 | |||
75 | static ssize_t node_read_numastat(struct sys_device * dev, char * buf) | ||
76 | { | ||
77 | unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign; | ||
78 | unsigned long local_node, other_node; | ||
79 | int i, cpu; | ||
80 | pg_data_t *pg = NODE_DATA(dev->id); | ||
81 | numa_hit = 0; | ||
82 | numa_miss = 0; | ||
83 | interleave_hit = 0; | ||
84 | numa_foreign = 0; | ||
85 | local_node = 0; | ||
86 | other_node = 0; | ||
87 | for (i = 0; i < MAX_NR_ZONES; i++) { | ||
88 | struct zone *z = &pg->node_zones[i]; | ||
89 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
90 | struct per_cpu_pageset *ps = &z->pageset[cpu]; | ||
91 | numa_hit += ps->numa_hit; | ||
92 | numa_miss += ps->numa_miss; | ||
93 | numa_foreign += ps->numa_foreign; | ||
94 | interleave_hit += ps->interleave_hit; | ||
95 | local_node += ps->local_node; | ||
96 | other_node += ps->other_node; | ||
97 | } | ||
98 | } | ||
99 | return sprintf(buf, | ||
100 | "numa_hit %lu\n" | ||
101 | "numa_miss %lu\n" | ||
102 | "numa_foreign %lu\n" | ||
103 | "interleave_hit %lu\n" | ||
104 | "local_node %lu\n" | ||
105 | "other_node %lu\n", | ||
106 | numa_hit, | ||
107 | numa_miss, | ||
108 | numa_foreign, | ||
109 | interleave_hit, | ||
110 | local_node, | ||
111 | other_node); | ||
112 | } | ||
113 | static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); | ||
114 | |||
115 | static ssize_t node_read_distance(struct sys_device * dev, char * buf) | ||
116 | { | ||
117 | int nid = dev->id; | ||
118 | int len = 0; | ||
119 | int i; | ||
120 | |||
121 | /* buf currently PAGE_SIZE, need ~4 chars per node */ | ||
122 | BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2); | ||
123 | |||
124 | for_each_online_node(i) | ||
125 | len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i)); | ||
126 | |||
127 | len += sprintf(buf + len, "\n"); | ||
128 | return len; | ||
129 | } | ||
130 | static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); | ||
131 | |||
132 | |||
133 | /* | ||
134 | * register_node - Setup a driverfs device for a node. | ||
135 | * @num - Node number to use when creating the device. | ||
136 | * | ||
137 | * Initialize and register the node device. | ||
138 | */ | ||
139 | int __init register_node(struct node *node, int num, struct node *parent) | ||
140 | { | ||
141 | int error; | ||
142 | |||
143 | node->sysdev.id = num; | ||
144 | node->sysdev.cls = &node_class; | ||
145 | error = sysdev_register(&node->sysdev); | ||
146 | |||
147 | if (!error){ | ||
148 | sysdev_create_file(&node->sysdev, &attr_cpumap); | ||
149 | sysdev_create_file(&node->sysdev, &attr_meminfo); | ||
150 | sysdev_create_file(&node->sysdev, &attr_numastat); | ||
151 | sysdev_create_file(&node->sysdev, &attr_distance); | ||
152 | } | ||
153 | return error; | ||
154 | } | ||
155 | |||
156 | |||
157 | int __init register_node_type(void) | ||
158 | { | ||
159 | return sysdev_class_register(&node_class); | ||
160 | } | ||
161 | postcore_initcall(register_node_type); | ||