Whamcloud - gitweb
LU-12352 libcfs: crashes with certain cpu part numbers
[fs/lustre-release.git] / libcfs / libcfs / libcfs_cpu.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * GPL HEADER END
17  */
18 /*
19  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
20  * Copyright (c) 2012, 2017, Intel Corporation.
21  */
22 /*
23  * This file is part of Lustre, http://www.lustre.org/
24  * Lustre is a trademark of Sun Microsystems, Inc.
25  *
26  * Please see comments in libcfs/include/libcfs/libcfs_cpu.h for introduction
27  *
28  * Author: liang@whamcloud.com
29  */
30
31 #define DEBUG_SUBSYSTEM S_LNET
32
33 #include <linux/cpu.h>
34 #include <linux/sched.h>
35 #include <libcfs/libcfs_cpu.h>
36 #include <libcfs/libcfs.h>
37
38 /** Global CPU partition table */
39 struct cfs_cpt_table *cfs_cpt_table __read_mostly;
40 EXPORT_SYMBOL(cfs_cpt_table);
41
42 /**
43  * modparam for setting number of partitions
44  *
45  *  0 : estimate best value based on cores or NUMA nodes
46  *  1 : disable multiple partitions
47  * >1 : specify number of partitions
48  */
49 static int cpu_npartitions;
50 module_param(cpu_npartitions, int, 0444);
51 MODULE_PARM_DESC(cpu_npartitions, "# of CPU partitions");
52
53 /**
54  * modparam for setting CPU partitions patterns:
55  *
56  * i.e: "0[0,1,2,3] 1[4,5,6,7]", number before bracket is CPU partition ID,
57  *      number in bracket is processor ID (core or HT)
58  *
59  * i.e: "N 0[0,1] 1[2,3]" the first character 'N' means numbers in bracket
60  *       are NUMA node ID, number before bracket is CPU partition ID.
61  *
62  * i.e: "N", shortcut expression to create CPT from NUMA & CPU topology
63  *
64  * NB: If user specified cpu_pattern, cpu_npartitions will be ignored
65  */
66 static char *cpu_pattern = "N";
67 module_param(cpu_pattern, charp, 0444);
68 MODULE_PARM_DESC(cpu_pattern, "CPU partitions pattern");
69
70 #ifdef CONFIG_SMP
71 struct cfs_cpt_table *cfs_cpt_table_alloc(int ncpt)
72 {
73         struct cfs_cpt_table *cptab;
74         int i;
75
76         LIBCFS_ALLOC(cptab, sizeof(*cptab));
77         if (!cptab)
78                 return NULL;
79
80         cptab->ctb_nparts = ncpt;
81
82         LIBCFS_ALLOC(cptab->ctb_cpumask, cpumask_size());
83         if (!cptab->ctb_cpumask)
84                 goto failed_alloc_cpumask;
85
86         LIBCFS_ALLOC(cptab->ctb_nodemask, sizeof(*cptab->ctb_nodemask));
87         if (!cptab->ctb_nodemask)
88                 goto failed_alloc_nodemask;
89
90         LIBCFS_ALLOC(cptab->ctb_cpu2cpt,
91                      nr_cpu_ids * sizeof(cptab->ctb_cpu2cpt[0]));
92         if (!cptab->ctb_cpu2cpt)
93                 goto failed_alloc_cpu2cpt;
94
95         memset(cptab->ctb_cpu2cpt, -1,
96                nr_cpu_ids * sizeof(cptab->ctb_cpu2cpt[0]));
97
98         LIBCFS_ALLOC(cptab->ctb_node2cpt,
99                      nr_node_ids * sizeof(cptab->ctb_node2cpt[0]));
100         if (!cptab->ctb_node2cpt)
101                 goto failed_alloc_node2cpt;
102
103         memset(cptab->ctb_node2cpt, -1,
104                nr_node_ids * sizeof(cptab->ctb_node2cpt[0]));
105
106         LIBCFS_ALLOC(cptab->ctb_parts, ncpt * sizeof(cptab->ctb_parts[0]));
107         if (!cptab->ctb_parts)
108                 goto failed_alloc_ctb_parts;
109
110         memset(cptab->ctb_parts, -1, ncpt * sizeof(cptab->ctb_parts[0]));
111
112         for (i = 0; i < ncpt; i++) {
113                 struct cfs_cpu_partition *part = &cptab->ctb_parts[i];
114
115                 LIBCFS_ALLOC(part->cpt_cpumask, cpumask_size());
116                 if (!part->cpt_cpumask)
117                         goto failed_setting_ctb_parts;
118
119                 LIBCFS_ALLOC(part->cpt_nodemask, sizeof(*part->cpt_nodemask));
120                 if (!part->cpt_nodemask)
121                         goto failed_setting_ctb_parts;
122
123                 LIBCFS_ALLOC(part->cpt_distance,
124                              cptab->ctb_nparts * sizeof(part->cpt_distance[0]));
125                 if (!part->cpt_distance)
126                         goto failed_setting_ctb_parts;
127
128                 memset(part->cpt_distance, -1,
129                        cptab->ctb_nparts * sizeof(part->cpt_distance[0]));
130         }
131
132         return cptab;
133
134 failed_setting_ctb_parts:
135         while (i-- >= 0) {
136                 struct cfs_cpu_partition *part = &cptab->ctb_parts[i];
137
138                 if (part->cpt_nodemask) {
139                         LIBCFS_FREE(part->cpt_nodemask,
140                                     sizeof(*part->cpt_nodemask));
141                 }
142
143                 if (part->cpt_cpumask)
144                         LIBCFS_FREE(part->cpt_cpumask, cpumask_size());
145
146                 if (part->cpt_distance) {
147                         LIBCFS_FREE(part->cpt_distance,
148                                 cptab->ctb_nparts *
149                                         sizeof(part->cpt_distance[0]));
150                 }
151         }
152
153         if (cptab->ctb_parts) {
154                 LIBCFS_FREE(cptab->ctb_parts,
155                             cptab->ctb_nparts * sizeof(cptab->ctb_parts[0]));
156         }
157 failed_alloc_ctb_parts:
158         if (cptab->ctb_node2cpt) {
159                 LIBCFS_FREE(cptab->ctb_node2cpt,
160                             nr_node_ids * sizeof(cptab->ctb_node2cpt[0]));
161         }
162 failed_alloc_node2cpt:
163         if (cptab->ctb_cpu2cpt) {
164                 LIBCFS_FREE(cptab->ctb_cpu2cpt,
165                             nr_cpu_ids * sizeof(cptab->ctb_cpu2cpt[0]));
166         }
167 failed_alloc_cpu2cpt:
168         if (cptab->ctb_nodemask)
169                 LIBCFS_FREE(cptab->ctb_nodemask, sizeof(*cptab->ctb_nodemask));
170 failed_alloc_nodemask:
171         if (cptab->ctb_cpumask)
172                 LIBCFS_FREE(cptab->ctb_cpumask, cpumask_size());
173 failed_alloc_cpumask:
174         LIBCFS_FREE(cptab, sizeof(*cptab));
175         return NULL;
176 }
177 EXPORT_SYMBOL(cfs_cpt_table_alloc);
178
179 void cfs_cpt_table_free(struct cfs_cpt_table *cptab)
180 {
181         int i;
182
183         if (cptab->ctb_cpu2cpt) {
184                 LIBCFS_FREE(cptab->ctb_cpu2cpt,
185                             nr_cpu_ids * sizeof(cptab->ctb_cpu2cpt[0]));
186         }
187
188         if (cptab->ctb_node2cpt) {
189                 LIBCFS_FREE(cptab->ctb_node2cpt,
190                             nr_node_ids * sizeof(cptab->ctb_node2cpt[0]));
191         }
192
193         for (i = 0; cptab->ctb_parts && i < cptab->ctb_nparts; i++) {
194                 struct cfs_cpu_partition *part = &cptab->ctb_parts[i];
195
196                 if (part->cpt_nodemask) {
197                         LIBCFS_FREE(part->cpt_nodemask,
198                                     sizeof(*part->cpt_nodemask));
199                 }
200
201                 if (part->cpt_cpumask)
202                         LIBCFS_FREE(part->cpt_cpumask, cpumask_size());
203
204                 if (part->cpt_distance) {
205                         LIBCFS_FREE(part->cpt_distance,
206                                 cptab->ctb_nparts *
207                                         sizeof(part->cpt_distance[0]));
208                 }
209         }
210
211         if (cptab->ctb_parts) {
212                 LIBCFS_FREE(cptab->ctb_parts,
213                             cptab->ctb_nparts * sizeof(cptab->ctb_parts[0]));
214         }
215
216         if (cptab->ctb_nodemask)
217                 LIBCFS_FREE(cptab->ctb_nodemask, sizeof(*cptab->ctb_nodemask));
218         if (cptab->ctb_cpumask)
219                 LIBCFS_FREE(cptab->ctb_cpumask, cpumask_size());
220
221         LIBCFS_FREE(cptab, sizeof(*cptab));
222 }
223 EXPORT_SYMBOL(cfs_cpt_table_free);
224
225 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len)
226 {
227         char *tmp = buf;
228         int rc;
229         int i;
230         int j;
231
232         for (i = 0; i < cptab->ctb_nparts; i++) {
233                 if (len <= 0)
234                         goto err;
235
236                 rc = snprintf(tmp, len, "%d\t:", i);
237                 len -= rc;
238
239                 if (len <= 0)
240                         goto err;
241
242                 tmp += rc;
243                 for_each_cpu(j, cptab->ctb_parts[i].cpt_cpumask) {
244                         rc = snprintf(tmp, len, " %d", j);
245                         len -= rc;
246                         if (len <= 0)
247                                 goto err;
248                         tmp += rc;
249                 }
250
251                 *tmp = '\n';
252                 tmp++;
253                 len--;
254         }
255
256         return tmp - buf;
257 err:
258         return -E2BIG;
259 }
260 EXPORT_SYMBOL(cfs_cpt_table_print);
261
262 int cfs_cpt_distance_print(struct cfs_cpt_table *cptab, char *buf, int len)
263 {
264         char *tmp = buf;
265         int rc;
266         int i;
267         int j;
268
269         for (i = 0; i < cptab->ctb_nparts; i++) {
270                 if (len <= 0)
271                         goto err;
272
273                 rc = snprintf(tmp, len, "%d\t:", i);
274                 len -= rc;
275
276                 if (len <= 0)
277                         goto err;
278
279                 tmp += rc;
280                 for (j = 0; j < cptab->ctb_nparts; j++) {
281                         rc = snprintf(tmp, len, " %d:%d", j,
282                                       cptab->ctb_parts[i].cpt_distance[j]);
283                         len -= rc;
284                         if (len <= 0)
285                                 goto err;
286                         tmp += rc;
287                 }
288
289                 *tmp = '\n';
290                 tmp++;
291                 len--;
292         }
293
294         return tmp - buf;
295 err:
296         return -E2BIG;
297 }
298 EXPORT_SYMBOL(cfs_cpt_distance_print);
299
300 int cfs_cpt_number(struct cfs_cpt_table *cptab)
301 {
302         return cptab->ctb_nparts;
303 }
304 EXPORT_SYMBOL(cfs_cpt_number);
305
306 int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt)
307 {
308         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
309
310         return cpt == CFS_CPT_ANY ?
311                cpumask_weight(cptab->ctb_cpumask) :
312                cpumask_weight(cptab->ctb_parts[cpt].cpt_cpumask);
313 }
314 EXPORT_SYMBOL(cfs_cpt_weight);
315
316 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt)
317 {
318         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
319
320         return cpt == CFS_CPT_ANY ?
321                cpumask_any_and(cptab->ctb_cpumask,
322                                cpu_online_mask) < nr_cpu_ids :
323                cpumask_any_and(cptab->ctb_parts[cpt].cpt_cpumask,
324                                cpu_online_mask) < nr_cpu_ids;
325 }
326 EXPORT_SYMBOL(cfs_cpt_online);
327
328 cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt)
329 {
330         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
331
332         return cpt == CFS_CPT_ANY ?
333                cptab->ctb_cpumask : cptab->ctb_parts[cpt].cpt_cpumask;
334 }
335 EXPORT_SYMBOL(cfs_cpt_cpumask);
336
337 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt)
338 {
339         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
340
341         return cpt == CFS_CPT_ANY ?
342                cptab->ctb_nodemask : cptab->ctb_parts[cpt].cpt_nodemask;
343 }
344 EXPORT_SYMBOL(cfs_cpt_nodemask);
345
346 unsigned int cfs_cpt_distance(struct cfs_cpt_table *cptab, int cpt1, int cpt2)
347 {
348         LASSERT(cpt1 == CFS_CPT_ANY || (cpt1 >= 0 && cpt1 < cptab->ctb_nparts));
349         LASSERT(cpt2 == CFS_CPT_ANY || (cpt2 >= 0 && cpt2 < cptab->ctb_nparts));
350
351         if (cpt1 == CFS_CPT_ANY || cpt2 == CFS_CPT_ANY)
352                 return cptab->ctb_distance;
353
354         return cptab->ctb_parts[cpt1].cpt_distance[cpt2];
355 }
356 EXPORT_SYMBOL(cfs_cpt_distance);
357
358 /*
359  * Calculate the maximum NUMA distance between all nodes in the
360  * from_mask and all nodes in the to_mask.
361  */
362 static unsigned int cfs_cpt_distance_calculate(nodemask_t *from_mask,
363                                                nodemask_t *to_mask)
364 {
365         unsigned int maximum;
366         unsigned int distance;
367         int from;
368         int to;
369
370         maximum = 0;
371         for_each_node_mask(from, *from_mask) {
372                 for_each_node_mask(to, *to_mask) {
373                         distance = node_distance(from, to);
374                         if (maximum < distance)
375                                 maximum = distance;
376                 }
377         }
378         return maximum;
379 }
380
381 static void cfs_cpt_add_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
382 {
383         cptab->ctb_cpu2cpt[cpu] = cpt;
384
385         cpumask_set_cpu(cpu, cptab->ctb_cpumask);
386         cpumask_set_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask);
387 }
388
389 static void cfs_cpt_del_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
390 {
391         cpumask_clear_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask);
392         cpumask_clear_cpu(cpu, cptab->ctb_cpumask);
393
394         cptab->ctb_cpu2cpt[cpu] = -1;
395 }
396
397 static void cfs_cpt_add_node(struct cfs_cpt_table *cptab, int cpt, int node)
398 {
399         struct cfs_cpu_partition *part;
400
401         if (!node_isset(node, *cptab->ctb_nodemask)) {
402                 unsigned int dist;
403
404                 /* first time node is added to the CPT table */
405                 node_set(node, *cptab->ctb_nodemask);
406                 cptab->ctb_node2cpt[node] = cpt;
407
408                 dist = cfs_cpt_distance_calculate(cptab->ctb_nodemask,
409                                                   cptab->ctb_nodemask);
410                 cptab->ctb_distance = dist;
411         }
412
413         part = &cptab->ctb_parts[cpt];
414         if (!node_isset(node, *part->cpt_nodemask)) {
415                 int cpt2;
416
417                 /* first time node is added to this CPT */
418                 node_set(node, *part->cpt_nodemask);
419                 for (cpt2 = 0; cpt2 < cptab->ctb_nparts; cpt2++) {
420                         struct cfs_cpu_partition *part2;
421                         unsigned int dist;
422
423                         part2 = &cptab->ctb_parts[cpt2];
424                         dist = cfs_cpt_distance_calculate(part->cpt_nodemask,
425                                                           part2->cpt_nodemask);
426                         part->cpt_distance[cpt2] = dist;
427                         dist = cfs_cpt_distance_calculate(part2->cpt_nodemask,
428                                                           part->cpt_nodemask);
429                         part2->cpt_distance[cpt] = dist;
430                 }
431         }
432 }
433
434 static void cfs_cpt_del_node(struct cfs_cpt_table *cptab, int cpt, int node)
435 {
436         struct cfs_cpu_partition *part = &cptab->ctb_parts[cpt];
437         int cpu;
438
439         for_each_cpu(cpu, part->cpt_cpumask) {
440                 /* this CPT has other CPU belonging to this node? */
441                 if (cpu_to_node(cpu) == node)
442                         break;
443         }
444
445         if (cpu >= nr_cpu_ids && node_isset(node,  *part->cpt_nodemask)) {
446                 int cpt2;
447
448                 /* No more CPUs in the node for this CPT. */
449                 node_clear(node, *part->cpt_nodemask);
450                 for (cpt2 = 0; cpt2 < cptab->ctb_nparts; cpt2++) {
451                         struct cfs_cpu_partition *part2;
452                         unsigned int dist;
453
454                         part2 = &cptab->ctb_parts[cpt2];
455                         if (node_isset(node, *part2->cpt_nodemask))
456                                 cptab->ctb_node2cpt[node] = cpt2;
457
458                         dist = cfs_cpt_distance_calculate(part->cpt_nodemask,
459                                                           part2->cpt_nodemask);
460                         part->cpt_distance[cpt2] = dist;
461                         dist = cfs_cpt_distance_calculate(part2->cpt_nodemask,
462                                                           part->cpt_nodemask);
463                         part2->cpt_distance[cpt] = dist;
464                 }
465         }
466
467         for_each_cpu(cpu, cptab->ctb_cpumask) {
468                 /* this CPT-table has other CPUs belonging to this node? */
469                 if (cpu_to_node(cpu) == node)
470                         break;
471         }
472
473         if (cpu >= nr_cpu_ids && node_isset(node, *cptab->ctb_nodemask)) {
474                 /* No more CPUs in the table for this node. */
475                 node_clear(node, *cptab->ctb_nodemask);
476                 cptab->ctb_node2cpt[node] = -1;
477                 cptab->ctb_distance =
478                         cfs_cpt_distance_calculate(cptab->ctb_nodemask,
479                                                    cptab->ctb_nodemask);
480         }
481 }
482
483 int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
484 {
485         LASSERT(cpt >= 0 && cpt < cptab->ctb_nparts);
486
487         if (cpu < 0 || cpu >= nr_cpu_ids || !cpu_online(cpu)) {
488                 CDEBUG(D_INFO, "CPU %d is invalid or it's offline\n", cpu);
489                 return 0;
490         }
491
492         if (cptab->ctb_cpu2cpt[cpu] != -1) {
493                 CDEBUG(D_INFO, "CPU %d is already in partition %d\n",
494                        cpu, cptab->ctb_cpu2cpt[cpu]);
495                 return 0;
496         }
497
498         if (cpumask_test_cpu(cpu, cptab->ctb_cpumask)) {
499                 CDEBUG(D_INFO, "CPU %d is already in cpumask\n", cpu);
500                 return 0;
501         }
502
503         if (cpumask_test_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask)) {
504                 CDEBUG(D_INFO, "CPU %d is already in partition %d cpumask\n",
505                        cpu, cptab->ctb_cpu2cpt[cpu]);
506                 return 0;
507         }
508
509         cfs_cpt_add_cpu(cptab, cpt, cpu);
510         cfs_cpt_add_node(cptab, cpt, cpu_to_node(cpu));
511
512         return 1;
513 }
514 EXPORT_SYMBOL(cfs_cpt_set_cpu);
515
516 void cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
517 {
518         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
519
520         if (cpu < 0 || cpu >= nr_cpu_ids) {
521                 CDEBUG(D_INFO, "Invalid CPU id %d\n", cpu);
522                 return;
523         }
524
525         if (cpt == CFS_CPT_ANY) {
526                 /* caller doesn't know the partition ID */
527                 cpt = cptab->ctb_cpu2cpt[cpu];
528                 if (cpt < 0) { /* not set in this CPT-table */
529                         CDEBUG(D_INFO,
530                                "Try to unset cpu %d which is not in CPT-table %p\n",
531                                cpt, cptab);
532                         return;
533                 }
534
535         } else if (cpt != cptab->ctb_cpu2cpt[cpu]) {
536                 CDEBUG(D_INFO,
537                        "CPU %d is not in CPU partition %d\n", cpu, cpt);
538                 return;
539         }
540
541         LASSERT(cpumask_test_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask));
542         LASSERT(cpumask_test_cpu(cpu, cptab->ctb_cpumask));
543
544         cfs_cpt_del_cpu(cptab, cpt, cpu);
545         cfs_cpt_del_node(cptab, cpt, cpu_to_node(cpu));
546 }
547 EXPORT_SYMBOL(cfs_cpt_unset_cpu);
548
549 int cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab, int cpt,
550                         const cpumask_t *mask)
551 {
552         int cpu;
553
554         if (!cpumask_weight(mask) ||
555             cpumask_any_and(mask, cpu_online_mask) >= nr_cpu_ids) {
556                 CDEBUG(D_INFO,
557                        "No online CPU is found in the CPU mask for CPU partition %d\n",
558                        cpt);
559                 return 0;
560         }
561
562         for_each_cpu(cpu, mask) {
563                 cfs_cpt_add_cpu(cptab, cpt, cpu);
564                 cfs_cpt_add_node(cptab, cpt, cpu_to_node(cpu));
565         }
566
567         return 1;
568 }
569 EXPORT_SYMBOL(cfs_cpt_set_cpumask);
570
571 void cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab, int cpt,
572                            const cpumask_t *mask)
573 {
574         int cpu;
575
576         for_each_cpu(cpu, mask) {
577                 cfs_cpt_del_cpu(cptab, cpt, cpu);
578                 cfs_cpt_del_node(cptab, cpt, cpu_to_node(cpu));
579         }
580 }
581 EXPORT_SYMBOL(cfs_cpt_unset_cpumask);
582
583 int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node)
584 {
585         const cpumask_t *mask;
586         int cpu;
587
588         if (node < 0 || node >= nr_node_ids) {
589                 CDEBUG(D_INFO,
590                        "Invalid NUMA id %d for CPU partition %d\n", node, cpt);
591                 return 0;
592         }
593
594         mask = cpumask_of_node(node);
595
596         for_each_cpu(cpu, mask)
597                 cfs_cpt_add_cpu(cptab, cpt, cpu);
598
599         cfs_cpt_add_node(cptab, cpt, node);
600
601         return 1;
602 }
603 EXPORT_SYMBOL(cfs_cpt_set_node);
604
605 void cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node)
606 {
607         const cpumask_t *mask;
608         int cpu;
609
610         if (node < 0 || node >= nr_node_ids) {
611                 CDEBUG(D_INFO,
612                        "Invalid NUMA id %d for CPU partition %d\n", node, cpt);
613                 return;
614         }
615
616         mask = cpumask_of_node(node);
617
618         for_each_cpu(cpu, mask)
619                 cfs_cpt_del_cpu(cptab, cpt, cpu);
620
621         cfs_cpt_del_node(cptab, cpt, node);
622 }
623 EXPORT_SYMBOL(cfs_cpt_unset_node);
624
625 int cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab, int cpt,
626                          const nodemask_t *mask)
627 {
628         int node;
629
630         for_each_node_mask(node, *mask)
631                 cfs_cpt_set_node(cptab, cpt, node);
632
633         return 1;
634 }
635 EXPORT_SYMBOL(cfs_cpt_set_nodemask);
636
637 void cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab, int cpt,
638                             const nodemask_t *mask)
639 {
640         int node;
641
642         for_each_node_mask(node, *mask)
643                 cfs_cpt_unset_node(cptab, cpt, node);
644 }
645 EXPORT_SYMBOL(cfs_cpt_unset_nodemask);
646
647 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt)
648 {
649         nodemask_t *mask;
650         int weight;
651         int rotor;
652         int node = 0;
653
654         /* convert CPU partition ID to HW node id */
655
656         if (cpt < 0 || cpt >= cptab->ctb_nparts) {
657                 mask = cptab->ctb_nodemask;
658                 rotor = cptab->ctb_spread_rotor++;
659         } else {
660                 mask = cptab->ctb_parts[cpt].cpt_nodemask;
661                 rotor = cptab->ctb_parts[cpt].cpt_spread_rotor++;
662                 node  = cptab->ctb_parts[cpt].cpt_node;
663         }
664
665         weight = nodes_weight(*mask);
666         if (weight > 0) {
667                 rotor %= weight;
668
669                 for_each_node_mask(node, *mask) {
670                         if (!rotor--)
671                                 return node;
672                 }
673         }
674
675         return node;
676 }
677 EXPORT_SYMBOL(cfs_cpt_spread_node);
678
679 int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap)
680 {
681         int cpu;
682         int cpt;
683
684         preempt_disable();
685         cpu = smp_processor_id();
686         cpt = cptab->ctb_cpu2cpt[cpu];
687
688         if (cpt < 0 && remap) {
689                 /* don't return negative value for safety of upper layer,
690                  * instead we shadow the unknown cpu to a valid partition ID
691                  */
692                 cpt = cpu % cptab->ctb_nparts;
693         }
694         preempt_enable();
695         return cpt;
696 }
697 EXPORT_SYMBOL(cfs_cpt_current);
698
699 int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu)
700 {
701         LASSERT(cpu >= 0 && cpu < nr_cpu_ids);
702
703         return cptab->ctb_cpu2cpt[cpu];
704 }
705 EXPORT_SYMBOL(cfs_cpt_of_cpu);
706
707 int cfs_cpt_of_node(struct cfs_cpt_table *cptab, int node)
708 {
709         if (node < 0 || node > nr_node_ids)
710                 return CFS_CPT_ANY;
711
712         return cptab->ctb_node2cpt[node];
713 }
714 EXPORT_SYMBOL(cfs_cpt_of_node);
715
716 int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt)
717 {
718         nodemask_t *nodemask;
719         cpumask_t *cpumask;
720         int cpu;
721         int rc;
722
723         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
724
725         if (cpt == CFS_CPT_ANY) {
726                 cpumask = cptab->ctb_cpumask;
727                 nodemask = cptab->ctb_nodemask;
728         } else {
729                 cpumask = cptab->ctb_parts[cpt].cpt_cpumask;
730                 nodemask = cptab->ctb_parts[cpt].cpt_nodemask;
731         }
732
733         if (!cpumask_intersects(cpumask, cpu_online_mask)) {
734                 CDEBUG(D_INFO,
735                        "No online CPU found in CPU partition %d, did someone do CPU hotplug on system? You might need to reload Lustre modules to keep system working well.\n",
736                         cpt);
737                 return -ENODEV;
738         }
739
740         for_each_online_cpu(cpu) {
741                 if (cpumask_test_cpu(cpu, cpumask))
742                         continue;
743
744                 rc = set_cpus_allowed_ptr(current, cpumask);
745                 set_mems_allowed(*nodemask);
746                 if (!rc)
747                         schedule(); /* switch to allowed CPU */
748
749                 return rc;
750         }
751
752         /* don't need to set affinity because all online CPUs are covered */
753         return 0;
754 }
755 EXPORT_SYMBOL(cfs_cpt_bind);
756
757 /**
758  * Choose max to \a number CPUs from \a node and set them in \a cpt.
759  * We always prefer to choose CPU in the same core/socket.
760  */
761 static int cfs_cpt_choose_ncpus(struct cfs_cpt_table *cptab, int cpt,
762                                 cpumask_t *node_mask, int number)
763 {
764         cpumask_t *socket_mask = NULL;
765         cpumask_t *core_mask = NULL;
766         int rc = 0;
767         int cpu;
768         int i;
769
770         LASSERT(number > 0);
771
772         if (number >= cpumask_weight(node_mask)) {
773                 while (!cpumask_empty(node_mask)) {
774                         cpu = cpumask_first(node_mask);
775                         cpumask_clear_cpu(cpu, node_mask);
776
777                         if (!cpu_online(cpu))
778                                 continue;
779
780                         rc = cfs_cpt_set_cpu(cptab, cpt, cpu);
781                         if (!rc)
782                                 return -EINVAL;
783                 }
784                 return 0;
785         }
786
787         /* allocate scratch buffer */
788         LIBCFS_ALLOC(socket_mask, cpumask_size());
789         LIBCFS_ALLOC(core_mask, cpumask_size());
790         if (!socket_mask || !core_mask) {
791                 rc = -ENOMEM;
792                 goto out;
793         }
794
795         while (!cpumask_empty(node_mask)) {
796                 cpu = cpumask_first(node_mask);
797
798                 /* get cpumask for cores in the same socket */
799                 cpumask_and(socket_mask, topology_core_cpumask(cpu), node_mask);
800                 while (!cpumask_empty(socket_mask)) {
801                         /* get cpumask for hts in the same core */
802                         cpumask_and(core_mask, topology_sibling_cpumask(cpu),
803                                     node_mask);
804
805                         for_each_cpu(i, core_mask) {
806                                 cpumask_clear_cpu(i, socket_mask);
807                                 cpumask_clear_cpu(i, node_mask);
808
809                                 if (!cpu_online(i))
810                                         continue;
811
812                                 rc = cfs_cpt_set_cpu(cptab, cpt, i);
813                                 if (!rc) {
814                                         rc = -EINVAL;
815                                         goto out;
816                                 }
817
818                                 if (!--number)
819                                         goto out;
820                         }
821                         cpu = cpumask_first(socket_mask);
822                 }
823         }
824
825 out:
826         if (core_mask)
827                 LIBCFS_FREE(core_mask, cpumask_size());
828         if (socket_mask)
829                 LIBCFS_FREE(socket_mask, cpumask_size());
830         return rc;
831 }
832
833 #define CPT_WEIGHT_MIN 4
834
835 static int cfs_cpt_num_estimate(void)
836 {
837         int nthr = cpumask_weight(topology_sibling_cpumask(smp_processor_id()));
838         int ncpu = num_online_cpus();
839         int ncpt = 1;
840
841         if (ncpu > CPT_WEIGHT_MIN)
842                 for (ncpt = 2; ncpu > 2 * nthr * ncpt; ncpt++)
843                         ; /* nothing */
844
845 #if (BITS_PER_LONG == 32)
846         /* config many CPU partitions on 32-bit system could consume
847          * too much memory
848          */
849         ncpt = min(2, ncpt);
850 #endif
851         while (ncpu % ncpt)
852                 ncpt--; /* worst case is 1 */
853
854         return ncpt;
855 }
856
857 static struct cfs_cpt_table *cfs_cpt_table_create(int ncpt)
858 {
859         struct cfs_cpt_table *cptab = NULL;
860         cpumask_t *node_mask = NULL;
861         int cpt = 0;
862         int node;
863         int num;
864         int rem;
865         int rc = 0;
866
867         num = cfs_cpt_num_estimate();
868         if (ncpt <= 0)
869                 ncpt = num;
870
871         if (ncpt > num_online_cpus()) {
872                 rc = -EINVAL;
873                 CERROR("libcfs: CPU partition count %d > cores %d: rc = %d\n",
874                        ncpt, num_online_cpus(), rc);
875                 goto failed;
876         }
877
878         if (ncpt > 4 * num) {
879                 CWARN("CPU partition number %d is larger than suggested value (%d), your system may have performance issue or run out of memory while under pressure\n",
880                       ncpt, num);
881         }
882
883         cptab = cfs_cpt_table_alloc(ncpt);
884         if (!cptab) {
885                 CERROR("Failed to allocate CPU map(%d)\n", ncpt);
886                 rc = -ENOMEM;
887                 goto failed;
888         }
889
890         LIBCFS_ALLOC(node_mask, cpumask_size());
891         if (!node_mask) {
892                 CERROR("Failed to allocate scratch cpumask\n");
893                 rc = -ENOMEM;
894                 goto failed;
895         }
896
897         num = num_online_cpus() / ncpt;
898         rem = num_online_cpus() % ncpt;
899         for_each_online_node(node) {
900                 cpumask_copy(node_mask, cpumask_of_node(node));
901
902                 while (cpt < ncpt && !cpumask_empty(node_mask)) {
903                         struct cfs_cpu_partition *part = &cptab->ctb_parts[cpt];
904                         int ncpu = cpumask_weight(part->cpt_cpumask);
905
906                         rc = cfs_cpt_choose_ncpus(cptab, cpt, node_mask,
907                                                   (rem > 0) + num - ncpu);
908                         if (rc < 0) {
909                                 rc = -EINVAL;
910                                 goto failed_mask;
911                         }
912
913                         ncpu = cpumask_weight(part->cpt_cpumask);
914                         if (ncpu == num + !!(rem > 0)) {
915                                 cpt++;
916                                 rem--;
917                         }
918                 }
919         }
920
921         LIBCFS_FREE(node_mask, cpumask_size());
922
923         return cptab;
924
925 failed_mask:
926         if (node_mask)
927                 LIBCFS_FREE(node_mask, cpumask_size());
928 failed:
929         CERROR("Failed (rc = %d) to setup CPU partition table with %d partitions, online HW NUMA nodes: %d, HW CPU cores: %d.\n",
930                rc, ncpt, num_online_nodes(), num_online_cpus());
931
932         if (cptab)
933                 cfs_cpt_table_free(cptab);
934
935         return ERR_PTR(rc);
936 }
937
938 static struct cfs_cpt_table *cfs_cpt_table_create_pattern(const char *pattern)
939 {
940         struct cfs_cpt_table *cptab;
941         char *pattern_dup;
942         char *bracket;
943         char *str;
944         int node = 0;
945         int ncpt = 0;
946         int cpt = 0;
947         int high;
948         int rc;
949         int c;
950         int i;
951
952         pattern_dup = kstrdup(pattern, GFP_KERNEL);
953         if (!pattern_dup) {
954                 CERROR("Failed to duplicate pattern '%s'\n", pattern);
955                 return ERR_PTR(-ENOMEM);
956         }
957
958         str = strim(pattern_dup);
959         if (*str == 'n' || *str == 'N') {
960                 str++; /* skip 'N' char */
961                 node = 1; /* NUMA pattern */
962                 if (*str == '\0') {
963                         node = -1;
964                         for_each_online_node(i) {
965                                 if (!cpumask_empty(cpumask_of_node(i)))
966                                         ncpt++;
967                         }
968                         if (ncpt == 1) { /* single NUMA node */
969                                 kfree(pattern_dup);
970                                 return cfs_cpt_table_create(cpu_npartitions);
971                         }
972                 }
973         }
974
975         if (!ncpt) { /* scanning bracket which is mark of partition */
976                 bracket = str;
977                 while ((bracket = strchr(bracket, '['))) {
978                         bracket++;
979                         ncpt++;
980                 }
981         }
982
983         if (!ncpt ||
984             (node && ncpt > num_online_nodes()) ||
985             (!node && ncpt > num_online_cpus())) {
986                 CERROR("Invalid pattern '%s', or too many partitions %d\n",
987                        pattern_dup, ncpt);
988                 rc = -EINVAL;
989                 goto err_free_str;
990         }
991
992         cptab = cfs_cpt_table_alloc(ncpt);
993         if (!cptab) {
994                 CERROR("Failed to allocate CPU partition table\n");
995                 rc = -ENOMEM;
996                 goto err_free_str;
997         }
998
999         if (node < 0) { /* shortcut to create CPT from NUMA & CPU topology */
1000                 for_each_online_node(i) {
1001                         if (cpumask_empty(cpumask_of_node(i)))
1002                                 continue;
1003
1004                         rc = cfs_cpt_set_node(cptab, cpt++, i);
1005                         if (!rc) {
1006                                 rc = -EINVAL;
1007                                 goto err_free_table;
1008                         }
1009                 }
1010                 kfree(pattern_dup);
1011                 return cptab;
1012         }
1013
1014         high = node ? nr_node_ids - 1 : nr_cpu_ids - 1;
1015
1016         for (str = strim(str), c = 0; /* until break */; c++) {
1017                 struct cfs_range_expr *range;
1018                 struct cfs_expr_list *el;
1019                 int n;
1020
1021                 bracket = strchr(str, '[');
1022                 if (!bracket) {
1023                         if (*str) {
1024                                 CERROR("Invalid pattern '%s'\n", str);
1025                                 rc = -EINVAL;
1026                                 goto err_free_table;
1027                         } else if (c != ncpt) {
1028                                 CERROR("Expect %d partitions but found %d\n",
1029                                        ncpt, c);
1030                                 rc = -EINVAL;
1031                                 goto err_free_table;
1032                         }
1033                         break;
1034                 }
1035
1036                 if (sscanf(str, "%d%n", &cpt, &n) < 1) {
1037                         CERROR("Invalid CPU pattern '%s'\n", str);
1038                         rc = -EINVAL;
1039                         goto err_free_table;
1040                 }
1041
1042                 if (cpt < 0 || cpt >= ncpt) {
1043                         CERROR("Invalid partition id %d, total partitions %d\n",
1044                                cpt, ncpt);
1045                         rc = -EINVAL;
1046                         goto err_free_table;
1047                 }
1048
1049                 if (cfs_cpt_weight(cptab, cpt)) {
1050                         CERROR("Partition %d has already been set.\n", cpt);
1051                         rc = -EPERM;
1052                         goto err_free_table;
1053                 }
1054
1055                 str = strim(str + n);
1056                 if (str != bracket) {
1057                         CERROR("Invalid pattern '%s'\n", str);
1058                         rc = -EINVAL;
1059                         goto err_free_table;
1060                 }
1061
1062                 bracket = strchr(str, ']');
1063                 if (!bracket) {
1064                         CERROR("Missing right bracket for partition %d in '%s'\n",
1065                                cpt, str);
1066                         rc = -EINVAL;
1067                         goto err_free_table;
1068                 }
1069
1070                 rc = cfs_expr_list_parse(str, (bracket - str) + 1, 0, high,
1071                                          &el);
1072                 if (rc) {
1073                         CERROR("Can't parse number range in '%s'\n", str);
1074                         rc = -ERANGE;
1075                         goto err_free_table;
1076                 }
1077
1078                 list_for_each_entry(range, &el->el_exprs, re_link) {
1079                         for (i = range->re_lo; i <= range->re_hi; i++) {
1080                                 if ((i - range->re_lo) % range->re_stride)
1081                                         continue;
1082
1083                                 rc = node ? cfs_cpt_set_node(cptab, cpt, i)
1084                                           : cfs_cpt_set_cpu(cptab, cpt, i);
1085                                 if (!rc) {
1086                                         cfs_expr_list_free(el);
1087                                         rc = -EINVAL;
1088                                         goto err_free_table;
1089                                 }
1090                         }
1091                 }
1092
1093                 cfs_expr_list_free(el);
1094
1095                 if (!cfs_cpt_online(cptab, cpt)) {
1096                         CERROR("No online CPU is found on partition %d\n", cpt);
1097                         rc = -ENODEV;
1098                         goto err_free_table;
1099                 }
1100
1101                 str = strim(bracket + 1);
1102         }
1103
1104         kfree(pattern_dup);
1105         return cptab;
1106
1107 err_free_table:
1108         cfs_cpt_table_free(cptab);
1109 err_free_str:
1110         kfree(pattern_dup);
1111         return ERR_PTR(rc);
1112 }
1113
1114 #ifdef CONFIG_HOTPLUG_CPU
1115 #ifdef HAVE_HOTPLUG_STATE_MACHINE
1116 static enum cpuhp_state lustre_cpu_online;
1117
1118 static int cfs_cpu_online(unsigned int cpu)
1119 {
1120         return 0;
1121 }
1122 #endif
1123
1124 static int cfs_cpu_dead(unsigned int cpu)
1125 {
1126         bool warn;
1127
1128         /* if all HTs in a core are offline, it may break affinity */
1129         warn = cpumask_any_and(topology_sibling_cpumask(cpu),
1130                                cpu_online_mask) >= nr_cpu_ids;
1131         CDEBUG(warn ? D_WARNING : D_INFO,
1132                "Lustre: can't support CPU plug-out well now, performance and stability could be impacted [CPU %u]\n",
1133                cpu);
1134         return 0;
1135 }
1136
1137 #ifndef HAVE_HOTPLUG_STATE_MACHINE
1138 static int cfs_cpu_notify(struct notifier_block *self, unsigned long action,
1139                           void *hcpu)
1140 {
1141         int cpu = (unsigned long)hcpu;
1142
1143         switch (action) {
1144         case CPU_DEAD:
1145         case CPU_DEAD_FROZEN:
1146         case CPU_ONLINE:
1147         case CPU_ONLINE_FROZEN:
1148         default:
1149                 if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) {
1150                         CDEBUG(D_INFO, "CPU changed [cpu %u action %lx]\n",
1151                                cpu, action);
1152                         break;
1153                 }
1154
1155                 cfs_cpu_dead(cpu);
1156         }
1157
1158         return NOTIFY_OK;
1159 }
1160
1161 static struct notifier_block cfs_cpu_notifier = {
1162         .notifier_call  = cfs_cpu_notify,
1163         .priority       = 0
1164 };
1165 #endif /* !HAVE_HOTPLUG_STATE_MACHINE */
1166 #endif /* CONFIG_HOTPLUG_CPU */
1167
1168 void cfs_cpu_fini(void)
1169 {
1170         if (!IS_ERR_OR_NULL(cfs_cpt_table))
1171                 cfs_cpt_table_free(cfs_cpt_table);
1172
1173 #ifdef CONFIG_HOTPLUG_CPU
1174 #ifdef HAVE_HOTPLUG_STATE_MACHINE
1175         if (lustre_cpu_online > 0)
1176                 cpuhp_remove_state_nocalls(lustre_cpu_online);
1177         cpuhp_remove_state_nocalls(CPUHP_LUSTRE_CFS_DEAD);
1178 #else
1179         unregister_hotcpu_notifier(&cfs_cpu_notifier);
1180 #endif /* !HAVE_HOTPLUG_STATE_MACHINE */
1181 #endif /* CONFIG_HOTPLUG_CPU */
1182 }
1183
1184 int cfs_cpu_init(void)
1185 {
1186         int ret;
1187
1188         LASSERT(!cfs_cpt_table);
1189
1190 #ifdef CONFIG_HOTPLUG_CPU
1191 #ifdef HAVE_HOTPLUG_STATE_MACHINE
1192         ret = cpuhp_setup_state_nocalls(CPUHP_LUSTRE_CFS_DEAD,
1193                                         "fs/lustre/cfe:dead", NULL,
1194                                         cfs_cpu_dead);
1195         if (ret < 0)
1196                 goto failed_cpu_dead;
1197
1198         ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
1199                                         "fs/lustre/cfe:online",
1200                                         cfs_cpu_online, NULL);
1201         if (ret < 0)
1202                 goto failed_cpu_online;
1203
1204         lustre_cpu_online = ret;
1205 #else
1206         register_hotcpu_notifier(&cfs_cpu_notifier);
1207 #endif /* !HAVE_HOTPLUG_STATE_MACHINE */
1208 #endif /* CONFIG_HOTPLUG_CPU */
1209
1210         get_online_cpus();
1211         if (*cpu_pattern) {
1212                 cfs_cpt_table = cfs_cpt_table_create_pattern(cpu_pattern);
1213                 if (IS_ERR(cfs_cpt_table)) {
1214                         CERROR("Failed to create cptab from pattern '%s'\n",
1215                                cpu_pattern);
1216                         ret = PTR_ERR(cfs_cpt_table);
1217                         goto failed_alloc_table;
1218                 }
1219
1220         } else {
1221                 cfs_cpt_table = cfs_cpt_table_create(cpu_npartitions);
1222                 if (IS_ERR(cfs_cpt_table)) {
1223                         CERROR("Failed to create cptab with npartitions %d\n",
1224                                cpu_npartitions);
1225                         ret = PTR_ERR(cfs_cpt_table);
1226                         goto failed_alloc_table;
1227                 }
1228         }
1229
1230         put_online_cpus();
1231
1232         LCONSOLE(0, "HW NUMA nodes: %d, HW CPU cores: %d, npartitions: %d\n",
1233                  num_online_nodes(), num_online_cpus(),
1234                  cfs_cpt_number(cfs_cpt_table));
1235         return 0;
1236
1237 failed_alloc_table:
1238         put_online_cpus();
1239
1240         if (!IS_ERR_OR_NULL(cfs_cpt_table))
1241                 cfs_cpt_table_free(cfs_cpt_table);
1242
1243 #ifdef CONFIG_HOTPLUG_CPU
1244 #ifdef HAVE_HOTPLUG_STATE_MACHINE
1245         if (lustre_cpu_online > 0)
1246                 cpuhp_remove_state_nocalls(lustre_cpu_online);
1247 failed_cpu_online:
1248         cpuhp_remove_state_nocalls(CPUHP_LUSTRE_CFS_DEAD);
1249 failed_cpu_dead:
1250 #else
1251         unregister_hotcpu_notifier(&cfs_cpu_notifier);
1252 #endif /* !HAVE_HOTPLUG_STATE_MACHINE */
1253 #endif /* CONFIG_HOTPLUG_CPU */
1254         return ret;
1255 }
1256
1257 #else /* ! CONFIG_SMP */
1258
1259 struct cfs_cpt_table *cfs_cpt_table_alloc(int ncpt)
1260 {
1261         struct cfs_cpt_table *cptab;
1262
1263         if (ncpt != 1) {
1264                 CERROR("Can't support cpu partition number %d\n", ncpt);
1265                 return NULL;
1266         }
1267
1268         LIBCFS_ALLOC(cptab, sizeof(*cptab));
1269         if (!cptab)
1270                 return NULL;
1271
1272         cpumask_set_cpu(0, cptab->ctb_cpumask);
1273         node_set(0, cptab->ctb_nodemask);
1274
1275         return cptab;
1276 }
1277 EXPORT_SYMBOL(cfs_cpt_table_alloc);
1278
1279 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len)
1280 {
1281         int rc;
1282
1283         rc = snprintf(buf, len, "0\t: 0\n");
1284         len -= rc;
1285         if (len <= 0)
1286                 return -EFBIG;
1287
1288         return rc;
1289 }
1290 EXPORT_SYMBOL(cfs_cpt_table_print);
1291
1292 int cfs_cpt_distance_print(struct cfs_cpt_table *cptab, char *buf, int len)
1293 {
1294         int rc;
1295
1296         rc = snprintf(buf, len, "0\t: 0:1\n");
1297         len -= rc;
1298         if (len <= 0)
1299                 return -EFBIG;
1300
1301         return rc;
1302 }
1303 EXPORT_SYMBOL(cfs_cpt_distance_print);
1304
1305 void cfs_cpu_fini(void)
1306 {
1307         if (cfs_cpt_table) {
1308                 cfs_cpt_table_free(cfs_cpt_table);
1309                 cfs_cpt_table = NULL;
1310         }
1311 }
1312
1313 int cfs_cpu_init(void)
1314 {
1315         cfs_cpt_table = cfs_cpt_table_alloc(1);
1316
1317         return cfs_cpt_table ? 0 : -1;
1318 }
1319
1320 #endif /* !CONFIG_SMP */