• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /*                                                                            */
3 /* Copyright (c) Tejun Heo <tj@kernel.org>, 2009                              */
4 /*                                                                            */
5 /* This program is free software;  you can redistribute it and/or modify      */
6 /* it under the terms of the GNU General Public License as published by       */
7 /* the Free Software Foundation; either version 2 of the License, or          */
8 /* (at your option) any later version.                                        */
9 /*                                                                            */
10 /* This program is distributed in the hope that it will be useful,            */
11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
13 /* the GNU General Public License for more details.                           */
14 /*                                                                            */
15 /* You should have received a copy of the GNU General Public License          */
16 /* along with this program;  if not, write to the Free Software               */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
18 /*                                                                            */
19 /******************************************************************************/
20 #include <linux/module.h>
21 #include <linux/device.h>
22 #include <linux/sysfs.h>
23 #include <linux/percpu.h>
24 
pcpu_dump_chunk_slots(void)25 static inline void pcpu_dump_chunk_slots(void)
26 {
27 }
28 
29 struct alloc_cmd {
30 	size_t size;
31 	int marker;
32 };
33 
34 static const struct alloc_cmd cmds[] = {
35 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
36 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
37 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
38 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
39 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
40 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
41 	{256, 0}, {256, 1}, {256, 0}, {256, 1},
42 	{256, 0}, {256, 1}, {256, 0}, {256, 1},	/* 8k */
43 
44 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
45 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
46 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
47 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
48 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
49 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
50 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},
51 	{1024, 2}, {1024, 2}, {1024, 2}, {1024, 2},	/* 32k */
52 
53 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
54 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
55 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
56 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
57 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
58 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
59 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},
60 	{8192, 3}, {8192, 3}, {8192, 3}, {8192, 3},	/* 128k */
61 
62 	{0, 0},			/* free 0s */
63 
64 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
65 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
66 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
67 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
68 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
69 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
70 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
71 	{128, 4}, {128, 4}, {128, 4}, {128, 4},
72 	{128, 4}, {128, 4}, {128, 4}, {128, 4},	/* 4.5k */
73 
74 	{0, 1},			/* free 1s */
75 
76 	{1024, 5}, {1024, 5}, {1024, 5}, {1024, 5},	/* 4k */
77 
78 	{0, 5},			/* free 5s */
79 	{0, 4},
80 	{0, 3},
81 	{0, 2},
82 };
83 
84 #define NR_CMDS		ARRAY_SIZE(cmds)
85 
86 static void *ptrs[NR_CMDS];
87 
seed_val(unsigned int cmdno,unsigned int cpu)88 static unsigned long seed_val(unsigned int cmdno, unsigned int cpu)
89 {
90 	return 0xdeadbeefbeefdeadULL
91 	    + cmdno + (cmdno << 16) + (cpu << 8) + (cpu << 24);
92 }
93 
fill_area(void * p,size_t size,unsigned int cmdno)94 static void fill_area(void *p, size_t size, unsigned int cmdno)
95 {
96 	unsigned int cpu;
97 
98 	for_each_possible_cpu(cpu) {
99 		unsigned long v = seed_val(cmdno, cpu);
100 		unsigned long *up = per_cpu_ptr(p, cpu);
101 		size_t left = size;
102 
103 		while (left >= sizeof(unsigned long)) {
104 			*up++ = v++;
105 			left -= sizeof(unsigned long);
106 		}
107 	}
108 }
109 
verify_area(void * p,size_t size,unsigned int cmdno)110 static void verify_area(void *p, size_t size, unsigned int cmdno)
111 {
112 	unsigned int warns = 5;
113 	unsigned int cpu;
114 
115 	for_each_possible_cpu(cpu) {
116 		unsigned long v = seed_val(cmdno, cpu);
117 		unsigned long *up = per_cpu_ptr(p, cpu);
118 		size_t left = size;
119 
120 		while (left >= sizeof(unsigned long)) {
121 			if (*up != v && warns-- > 0) {
122 				printk
123 				    ("MISMATCH: cmdno=%u size=%zu cpu=%u off=%zu p=%p\n",
124 				     cmdno, size, cpu, size - left, p);
125 				printk("          [%p]=%lx should be %lx\n", up,
126 				       *up, v);
127 			}
128 			up++;
129 			v++;
130 			left -= sizeof(unsigned long);
131 		}
132 	}
133 }
134 
free_cmd(unsigned int cmdno)135 static void free_cmd(unsigned int cmdno)
136 {
137 	if (!ptrs[cmdno])
138 		return;
139 
140 	verify_area(ptrs[cmdno], cmds[cmdno].size, cmdno);
141 	free_percpu(ptrs[cmdno]);
142 	ptrs[cmdno] = NULL;
143 }
144 
run_test(void)145 static void run_test(void)
146 {
147 	unsigned int i, j;
148 
149 	for (i = 0; i < NR_CMDS; i++) {
150 		const struct alloc_cmd *cmd = &cmds[i];
151 
152 		if (cmd->size) {
153 			printk("ALLOC: %zu bytes marker=%d\n",
154 			       cmd->size, cmd->marker);
155 			ptrs[i] = __alloc_percpu(cmd->size,
156 						 __alignof__(unsigned long
157 							     long));
158 			if (ptrs[i])
159 				fill_area(ptrs[i], cmd->size, i);
160 			else
161 				printk("failed to allocate %zu bytes\n",
162 				       cmd->size);
163 			continue;
164 		}
165 
166 		printk("FREE: marker=%d\n", cmd->marker);
167 		pcpu_dump_chunk_slots();
168 		for (j = 0; j < i; j++)
169 			if (cmds[j].marker == cmd->marker)
170 				free_cmd(j);
171 		printk("FREE: done\n");
172 		pcpu_dump_chunk_slots();
173 	}
174 }
175 
176 struct stupid_large_alignment_struct {
177 	int a;
178 	int b;
179 	int c;
180 } __aligned(2048);
181 
182 struct stupid_large_struct {
183 	char a[1024];
184 };
185 
186 static DEFINE_PER_CPU(struct stupid_large_alignment_struct, blah_blah);
187 DEFINE_PER_CPU(struct stupid_large_struct, blah_blah2);
188 DEFINE_PER_CPU(struct stupid_large_struct, blah_blah3);
189 DEFINE_PER_CPU(struct stupid_large_struct, blah_blah4);
190 DEFINE_PER_CPU(struct stupid_large_struct, blah_blah5);
191 DEFINE_PER_CPU(struct stupid_large_struct, blah_blah6);
192 
test_init(void)193 static int __init test_init(void)
194 {
195 	unsigned int cpu;
196 
197 	printk("XXX test_pcpu:");
198 	for_each_possible_cpu(cpu)
199 	    printk(" %p", &per_cpu(blah_blah, cpu));
200 	printk("\n");
201 	pcpu_dump_chunk_slots();
202 
203 	run_test();
204 	return 0;
205 }
206 
test_exit(void)207 static void __exit test_exit(void)
208 {
209 	unsigned int i;
210 
211 	printk("XXX cleaning up\n");
212 	pcpu_dump_chunk_slots();
213 
214 	for (i = 0; i < NR_CMDS; i++)
215 		free_cmd(i);
216 
217 	printk("XXX done\n");
218 	pcpu_dump_chunk_slots();
219 }
220 
221 module_init(test_init);
222 module_exit(test_exit);
223 MODULE_LICENSE("GPL");
224