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