Whamcloud - gitweb
LU-8703 libcfs: remove usless CPU partition code
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-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  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25  *
26  * Copyright (c) 2012, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * Author: liang@whamcloud.com
33  */
34
35 #define DEBUG_SUBSYSTEM S_LNET
36
37 #include <linux/cpu.h>
38 #include <linux/sched.h>
39 #include <libcfs/libcfs.h>
40
41 #ifdef CONFIG_SMP
42
43 /**
44  * modparam for setting number of partitions
45  *
46  *  0 : estimate best value based on cores or NUMA nodes
47  *  1 : disable multiple partitions
48  * >1 : specify number of partitions
49  */
50 static int      cpu_npartitions;
51 module_param(cpu_npartitions, int, 0444);
52 MODULE_PARM_DESC(cpu_npartitions, "# of CPU partitions");
53
54 /**
55  * modparam for setting CPU partitions patterns:
56  *
57  * i.e: "0[0,1,2,3] 1[4,5,6,7]", number before bracket is CPU partition ID,
58  *      number in bracket is processor ID (core or HT)
59  *
60  * i.e: "N 0[0,1] 1[2,3]" the first character 'N' means numbers in bracket
61  *       are NUMA node ID, number before bracket is CPU partition ID.
62  *
63  * i.e: "N", shortcut expression to create CPT from NUMA & CPU topology
64  *
65  * NB: If user specified cpu_pattern, cpu_npartitions will be ignored
66  */
67 static char     *cpu_pattern = "N";
68 module_param(cpu_pattern, charp, 0444);
69 MODULE_PARM_DESC(cpu_pattern, "CPU partitions pattern");
70
71 /* return number of HTs in the same core of \a cpu */
72 int
73 cfs_cpu_ht_nsiblings(int cpu)
74 {
75         return cpumask_weight(topology_sibling_cpumask(cpu));
76 }
77 EXPORT_SYMBOL(cfs_cpu_ht_nsiblings);
78
79 void
80 cfs_cpt_table_free(struct cfs_cpt_table *cptab)
81 {
82         int i;
83
84         if (cptab->ctb_cpu2cpt != NULL) {
85                 LIBCFS_FREE(cptab->ctb_cpu2cpt,
86                             num_possible_cpus() *
87                             sizeof(cptab->ctb_cpu2cpt[0]));
88         }
89
90         for (i = 0; cptab->ctb_parts != NULL && i < cptab->ctb_nparts; i++) {
91                 struct cfs_cpu_partition *part = &cptab->ctb_parts[i];
92
93                 if (part->cpt_nodemask != NULL) {
94                         LIBCFS_FREE(part->cpt_nodemask,
95                                     sizeof(*part->cpt_nodemask));
96                 }
97
98                 if (part->cpt_cpumask != NULL)
99                         LIBCFS_FREE(part->cpt_cpumask, cpumask_size());
100         }
101
102         if (cptab->ctb_parts != NULL) {
103                 LIBCFS_FREE(cptab->ctb_parts,
104                             cptab->ctb_nparts * sizeof(cptab->ctb_parts[0]));
105         }
106
107         if (cptab->ctb_nodemask != NULL)
108                 LIBCFS_FREE(cptab->ctb_nodemask, sizeof(*cptab->ctb_nodemask));
109         if (cptab->ctb_cpumask != NULL)
110                 LIBCFS_FREE(cptab->ctb_cpumask, cpumask_size());
111
112         LIBCFS_FREE(cptab, sizeof(*cptab));
113 }
114 EXPORT_SYMBOL(cfs_cpt_table_free);
115
116 struct cfs_cpt_table *
117 cfs_cpt_table_alloc(unsigned int ncpt)
118 {
119         struct cfs_cpt_table *cptab;
120         int     i;
121
122         LIBCFS_ALLOC(cptab, sizeof(*cptab));
123         if (cptab == NULL)
124                 return NULL;
125
126         cptab->ctb_nparts = ncpt;
127
128         LIBCFS_ALLOC(cptab->ctb_cpumask, cpumask_size());
129         LIBCFS_ALLOC(cptab->ctb_nodemask, sizeof(*cptab->ctb_nodemask));
130
131         if (cptab->ctb_cpumask == NULL || cptab->ctb_nodemask == NULL)
132                 goto failed;
133
134         LIBCFS_ALLOC(cptab->ctb_cpu2cpt,
135                      num_possible_cpus() * sizeof(cptab->ctb_cpu2cpt[0]));
136         if (cptab->ctb_cpu2cpt == NULL)
137                 goto failed;
138
139         memset(cptab->ctb_cpu2cpt, -1,
140                num_possible_cpus() * sizeof(cptab->ctb_cpu2cpt[0]));
141
142         LIBCFS_ALLOC(cptab->ctb_parts, ncpt * sizeof(cptab->ctb_parts[0]));
143         if (cptab->ctb_parts == NULL)
144                 goto failed;
145
146         for (i = 0; i < ncpt; i++) {
147                 struct cfs_cpu_partition *part = &cptab->ctb_parts[i];
148
149                 LIBCFS_ALLOC(part->cpt_cpumask, cpumask_size());
150                 LIBCFS_ALLOC(part->cpt_nodemask, sizeof(*part->cpt_nodemask));
151                 if (part->cpt_cpumask == NULL || part->cpt_nodemask == NULL)
152                         goto failed;
153         }
154
155         return cptab;
156
157 failed:
158         cfs_cpt_table_free(cptab);
159         return NULL;
160 }
161 EXPORT_SYMBOL(cfs_cpt_table_alloc);
162
163 int
164 cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len)
165 {
166         char    *tmp = buf;
167         int     rc = 0;
168         int     i;
169         int     j;
170
171         for (i = 0; i < cptab->ctb_nparts; i++) {
172                 if (len > 0) {
173                         rc = snprintf(tmp, len, "%d\t: ", i);
174                         len -= rc;
175                 }
176
177                 if (len <= 0) {
178                         rc = -EFBIG;
179                         goto out;
180                 }
181
182                 tmp += rc;
183                 for_each_cpu(j, cptab->ctb_parts[i].cpt_cpumask) {
184                         rc = snprintf(tmp, len, "%d ", j);
185                         len -= rc;
186                         if (len <= 0) {
187                                 rc = -EFBIG;
188                                 goto out;
189                         }
190                         tmp += rc;
191                 }
192
193                 *tmp = '\n';
194                 tmp++;
195                 len--;
196         }
197
198 out:
199         if (rc < 0)
200                 return rc;
201
202         return tmp - buf;
203 }
204 EXPORT_SYMBOL(cfs_cpt_table_print);
205
206 int
207 cfs_cpt_number(struct cfs_cpt_table *cptab)
208 {
209         return cptab->ctb_nparts;
210 }
211 EXPORT_SYMBOL(cfs_cpt_number);
212
213 int
214 cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt)
215 {
216         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
217
218         return cpt == CFS_CPT_ANY ?
219                cpumask_weight(cptab->ctb_cpumask) :
220                cpumask_weight(cptab->ctb_parts[cpt].cpt_cpumask);
221 }
222 EXPORT_SYMBOL(cfs_cpt_weight);
223
224 int
225 cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt)
226 {
227         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
228
229         return cpt == CFS_CPT_ANY ?
230                cpumask_any_and(cptab->ctb_cpumask,
231                                cpu_online_mask) < nr_cpu_ids :
232                cpumask_any_and(cptab->ctb_parts[cpt].cpt_cpumask,
233                                cpu_online_mask) < nr_cpu_ids;
234 }
235 EXPORT_SYMBOL(cfs_cpt_online);
236
237 cpumask_t *
238 cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt)
239 {
240         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
241
242         return cpt == CFS_CPT_ANY ?
243                cptab->ctb_cpumask : cptab->ctb_parts[cpt].cpt_cpumask;
244 }
245 EXPORT_SYMBOL(cfs_cpt_cpumask);
246
247 nodemask_t *
248 cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt)
249 {
250         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
251
252         return cpt == CFS_CPT_ANY ?
253                cptab->ctb_nodemask : cptab->ctb_parts[cpt].cpt_nodemask;
254 }
255 EXPORT_SYMBOL(cfs_cpt_nodemask);
256
257 int
258 cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
259 {
260         int     node;
261
262         LASSERT(cpt >= 0 && cpt < cptab->ctb_nparts);
263
264         if (cpu < 0 || cpu >= nr_cpu_ids || !cpu_online(cpu)) {
265                 CDEBUG(D_INFO, "CPU %d is invalid or it's offline\n", cpu);
266                 return 0;
267         }
268
269         if (cptab->ctb_cpu2cpt[cpu] != -1) {
270                 CDEBUG(D_INFO, "CPU %d is already in partition %d\n",
271                        cpu, cptab->ctb_cpu2cpt[cpu]);
272                 return 0;
273         }
274
275         cptab->ctb_cpu2cpt[cpu] = cpt;
276
277         LASSERT(!cpumask_test_cpu(cpu, cptab->ctb_cpumask));
278         LASSERT(!cpumask_test_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask));
279
280         cpumask_set_cpu(cpu, cptab->ctb_cpumask);
281         cpumask_set_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask);
282
283         node = cpu_to_node(cpu);
284
285         /* first CPU of @node in this CPT table */
286         if (!node_isset(node, *cptab->ctb_nodemask))
287                 node_set(node, *cptab->ctb_nodemask);
288
289         /* first CPU of @node in this partition */
290         if (!node_isset(node, *cptab->ctb_parts[cpt].cpt_nodemask))
291                 node_set(node, *cptab->ctb_parts[cpt].cpt_nodemask);
292
293         return 1;
294 }
295 EXPORT_SYMBOL(cfs_cpt_set_cpu);
296
297 void
298 cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu)
299 {
300         int     node;
301         int     i;
302
303         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
304
305         if (cpu < 0 || cpu >= nr_cpu_ids) {
306                 CDEBUG(D_INFO, "Invalid CPU id %d\n", cpu);
307                 return;
308         }
309
310         if (cpt == CFS_CPT_ANY) {
311                 /* caller doesn't know the partition ID */
312                 cpt = cptab->ctb_cpu2cpt[cpu];
313                 if (cpt < 0) { /* not set in this CPT-table */
314                         CDEBUG(D_INFO, "Try to unset cpu %d which is "
315                                        "not in CPT-table %p\n", cpt, cptab);
316                         return;
317                 }
318
319         } else if (cpt != cptab->ctb_cpu2cpt[cpu]) {
320                 CDEBUG(D_INFO,
321                        "CPU %d is not in cpu-partition %d\n", cpu, cpt);
322                 return;
323         }
324
325         LASSERT(cpumask_test_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask));
326         LASSERT(cpumask_test_cpu(cpu, cptab->ctb_cpumask));
327
328         cpumask_clear_cpu(cpu, cptab->ctb_parts[cpt].cpt_cpumask);
329         cpumask_clear_cpu(cpu, cptab->ctb_cpumask);
330         cptab->ctb_cpu2cpt[cpu] = -1;
331
332         node = cpu_to_node(cpu);
333
334         LASSERT(node_isset(node, *cptab->ctb_parts[cpt].cpt_nodemask));
335         LASSERT(node_isset(node, *cptab->ctb_nodemask));
336
337         for_each_cpu(i, cptab->ctb_parts[cpt].cpt_cpumask) {
338                 /* this CPT has other CPU belonging to this node? */
339                 if (cpu_to_node(i) == node)
340                         break;
341         }
342
343         if (i >= nr_cpu_ids)
344                 node_clear(node, *cptab->ctb_parts[cpt].cpt_nodemask);
345
346         for_each_cpu(i, cptab->ctb_cpumask) {
347                 /* this CPT-table has other CPU belonging to this node? */
348                 if (cpu_to_node(i) == node)
349                         break;
350         }
351
352         if (i >= nr_cpu_ids)
353                 node_clear(node, *cptab->ctb_nodemask);
354 }
355 EXPORT_SYMBOL(cfs_cpt_unset_cpu);
356
357 int
358 cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab, int cpt, const cpumask_t *mask)
359 {
360         int cpu;
361
362         if (cpumask_weight(mask) == 0 ||
363             cpumask_any_and(mask, cpu_online_mask) >= nr_cpu_ids) {
364                 CDEBUG(D_INFO, "No online CPU is found in the CPU mask "
365                                "for CPU partition %d\n", cpt);
366                 return 0;
367         }
368
369         for_each_cpu(cpu, mask) {
370                 if (!cfs_cpt_set_cpu(cptab, cpt, cpu))
371                         return 0;
372         }
373
374         return 1;
375 }
376 EXPORT_SYMBOL(cfs_cpt_set_cpumask);
377
378 void
379 cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab, int cpt,
380                       const cpumask_t *mask)
381 {
382         int cpu;
383
384         for_each_cpu(cpu, mask)
385                 cfs_cpt_unset_cpu(cptab, cpt, cpu);
386 }
387 EXPORT_SYMBOL(cfs_cpt_unset_cpumask);
388
389 int
390 cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node)
391 {
392         const cpumask_t *mask;
393         int             rc;
394
395         if (node < 0 || node >= MAX_NUMNODES) {
396                 CDEBUG(D_INFO,
397                        "Invalid NUMA id %d for CPU partition %d\n", node, cpt);
398                 return 0;
399         }
400
401         mask = cpumask_of_node(node);
402         rc = cfs_cpt_set_cpumask(cptab, cpt, mask);
403
404         return rc;
405 }
406 EXPORT_SYMBOL(cfs_cpt_set_node);
407
408 void
409 cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node)
410 {
411         const cpumask_t *mask;
412
413         if (node < 0 || node >= MAX_NUMNODES) {
414                 CDEBUG(D_INFO,
415                        "Invalid NUMA id %d for CPU partition %d\n", node, cpt);
416                 return;
417         }
418
419         mask = cpumask_of_node(node);
420         cfs_cpt_unset_cpumask(cptab, cpt, mask);
421
422 }
423 EXPORT_SYMBOL(cfs_cpt_unset_node);
424
425 int
426 cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab, int cpt, nodemask_t *mask)
427 {
428         int     i;
429
430         for_each_node_mask(i, *mask) {
431                 if (!cfs_cpt_set_node(cptab, cpt, i))
432                         return 0;
433         }
434
435         return 1;
436 }
437 EXPORT_SYMBOL(cfs_cpt_set_nodemask);
438
439 void
440 cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab, int cpt, nodemask_t *mask)
441 {
442         int     i;
443
444         for_each_node_mask(i, *mask)
445                 cfs_cpt_unset_node(cptab, cpt, i);
446 }
447 EXPORT_SYMBOL(cfs_cpt_unset_nodemask);
448
449 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt)
450 {
451         nodemask_t      *mask;
452         int             weight;
453         int             rotor;
454         int             node;
455
456         /* convert CPU partition ID to HW node id */
457
458         if (cpt < 0 || cpt >= cptab->ctb_nparts) {
459                 mask = cptab->ctb_nodemask;
460                 rotor = cptab->ctb_spread_rotor++;
461         } else {
462                 mask = cptab->ctb_parts[cpt].cpt_nodemask;
463                 rotor = cptab->ctb_parts[cpt].cpt_spread_rotor++;
464         }
465
466         weight = nodes_weight(*mask);
467         LASSERT(weight > 0);
468
469         rotor %= weight;
470
471         for_each_node_mask(node, *mask) {
472                 if (rotor-- == 0)
473                         return node;
474         }
475
476         LBUG();
477         return 0;
478 }
479 EXPORT_SYMBOL(cfs_cpt_spread_node);
480
481 int
482 cfs_cpt_current(struct cfs_cpt_table *cptab, int remap)
483 {
484         int     cpu = smp_processor_id();
485         int     cpt = cptab->ctb_cpu2cpt[cpu];
486
487         if (cpt < 0) {
488                 if (!remap)
489                         return cpt;
490
491                 /* don't return negative value for safety of upper layer,
492                  * instead we shadow the unknown cpu to a valid partition ID */
493                 cpt = cpu % cptab->ctb_nparts;
494         }
495
496         return cpt;
497 }
498 EXPORT_SYMBOL(cfs_cpt_current);
499
500 int
501 cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu)
502 {
503         LASSERT(cpu >= 0 && cpu < nr_cpu_ids);
504
505         return cptab->ctb_cpu2cpt[cpu];
506 }
507 EXPORT_SYMBOL(cfs_cpt_of_cpu);
508
509 int
510 cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt)
511 {
512         cpumask_t       *cpumask;
513         nodemask_t      *nodemask;
514         int             rc;
515         int             i;
516
517         LASSERT(cpt == CFS_CPT_ANY || (cpt >= 0 && cpt < cptab->ctb_nparts));
518
519         if (cpt == CFS_CPT_ANY) {
520                 cpumask = cptab->ctb_cpumask;
521                 nodemask = cptab->ctb_nodemask;
522         } else {
523                 cpumask = cptab->ctb_parts[cpt].cpt_cpumask;
524                 nodemask = cptab->ctb_parts[cpt].cpt_nodemask;
525         }
526
527         if (cpumask_any_and(cpumask, cpu_online_mask) >= nr_cpu_ids) {
528                 CERROR("No online CPU found in CPU partition %d, did someone "
529                        "do CPU hotplug on system? You might need to reload "
530                        "Lustre modules to keep system working well.\n", cpt);
531                 return -EINVAL;
532         }
533
534         for_each_online_cpu(i) {
535                 if (cpumask_test_cpu(i, cpumask))
536                         continue;
537
538                 rc = set_cpus_allowed_ptr(current, cpumask);
539                 set_mems_allowed(*nodemask);
540                 if (rc == 0)
541                         schedule(); /* switch to allowed CPU */
542
543                 return rc;
544         }
545
546         /* don't need to set affinity because all online CPUs are covered */
547         return 0;
548 }
549 EXPORT_SYMBOL(cfs_cpt_bind);
550
551 /**
552  * Choose max to \a number CPUs from \a node and set them in \a cpt.
553  * We always prefer to choose CPU in the same core/socket.
554  */
555 static int
556 cfs_cpt_choose_ncpus(struct cfs_cpt_table *cptab, int cpt,
557                      cpumask_t *node, int number)
558 {
559         cpumask_t       *socket = NULL;
560         cpumask_t       *core = NULL;
561         int             rc = 0;
562         int             cpu;
563
564         LASSERT(number > 0);
565
566         if (number >= cpumask_weight(node)) {
567                 while (!cpumask_empty(node)) {
568                         cpu = cpumask_first(node);
569
570                         rc = cfs_cpt_set_cpu(cptab, cpt, cpu);
571                         if (!rc)
572                                 return -EINVAL;
573                         cpumask_clear_cpu(cpu, node);
574                 }
575                 return 0;
576         }
577
578         /* allocate scratch buffer */
579         LIBCFS_ALLOC(socket, cpumask_size());
580         LIBCFS_ALLOC(core, cpumask_size());
581         if (socket == NULL || core == NULL) {
582                 rc = -ENOMEM;
583                 goto out;
584         }
585
586         while (!cpumask_empty(node)) {
587                 cpu = cpumask_first(node);
588
589                 /* get cpumask for cores in the same socket */
590                 cpumask_copy(socket, topology_core_cpumask(cpu));
591                 cpumask_and(socket, socket, node);
592
593                 LASSERT(!cpumask_empty(socket));
594
595                 while (!cpumask_empty(socket)) {
596                         int     i;
597
598                         /* get cpumask for hts in the same core */
599                         cpumask_copy(core, topology_sibling_cpumask(cpu));
600                         cpumask_and(core, core, node);
601
602                         LASSERT(!cpumask_empty(core));
603
604                         for_each_cpu(i, core) {
605                                 cpumask_clear_cpu(i, socket);
606                                 cpumask_clear_cpu(i, node);
607
608                                 rc = cfs_cpt_set_cpu(cptab, cpt, i);
609                                 if (!rc) {
610                                         rc = -EINVAL;
611                                         goto out;
612                                 }
613
614                                 if (--number == 0)
615                                         goto out;
616                         }
617                         cpu = cpumask_first(socket);
618                 }
619         }
620
621 out:
622         if (socket != NULL)
623                 LIBCFS_FREE(socket, cpumask_size());
624         if (core != NULL)
625                 LIBCFS_FREE(core, cpumask_size());
626         return rc;
627 }
628
629 #define CPT_WEIGHT_MIN  4u
630
631 static unsigned int
632 cfs_cpt_num_estimate(void)
633 {
634         unsigned nnode = num_online_nodes();
635         unsigned ncpu  = num_online_cpus();
636         unsigned ncpt;
637
638         if (ncpu <= CPT_WEIGHT_MIN) {
639                 ncpt = 1;
640                 goto out;
641         }
642
643         /* generate reasonable number of CPU partitions based on total number
644          * of CPUs, Preferred N should be power2 and match this condition:
645          * 2 * (N - 1)^2 < NCPUS <= 2 * N^2 */
646         for (ncpt = 2; ncpu > 2 * ncpt * ncpt; ncpt <<= 1) {}
647
648         if (ncpt <= nnode) { /* fat numa system */
649                 while (nnode > ncpt)
650                         nnode >>= 1;
651
652         } else { /* ncpt > nnode */
653                 while ((nnode << 1) <= ncpt)
654                         nnode <<= 1;
655         }
656
657         ncpt = nnode;
658
659 out:
660 #if (BITS_PER_LONG == 32)
661         /* config many CPU partitions on 32-bit system could consume
662          * too much memory */
663         ncpt = min(2U, ncpt);
664 #endif
665         while (ncpu % ncpt != 0)
666                 ncpt--; /* worst case is 1 */
667
668         return ncpt;
669 }
670
671 static struct cfs_cpt_table *
672 cfs_cpt_table_create(int ncpt)
673 {
674         struct cfs_cpt_table *cptab = NULL;
675         cpumask_t       *mask = NULL;
676         int             cpt = 0;
677         int             num;
678         int             rc;
679         int             i;
680
681         rc = cfs_cpt_num_estimate();
682         if (ncpt <= 0)
683                 ncpt = rc;
684
685         if (ncpt > num_online_cpus() || ncpt > 4 * rc) {
686                 CWARN("CPU partition number %d is larger than suggested "
687                       "value (%d), your system may have performance"
688                       "issue or run out of memory while under pressure\n",
689                       ncpt, rc);
690         }
691
692         if (num_online_cpus() % ncpt != 0) {
693                 CERROR("CPU number %d is not multiple of cpu_npartition %d, "
694                        "please try different cpu_npartitions value or"
695                        "set pattern string by cpu_pattern=STRING\n",
696                        (int)num_online_cpus(), ncpt);
697                 goto failed;
698         }
699
700         cptab = cfs_cpt_table_alloc(ncpt);
701         if (cptab == NULL) {
702                 CERROR("Failed to allocate CPU map(%d)\n", ncpt);
703                 goto failed;
704         }
705
706         num = num_online_cpus() / ncpt;
707         if (num == 0) {
708                 CERROR("CPU changed while setting CPU partition\n");
709                 goto failed;
710         }
711
712         LIBCFS_ALLOC(mask, cpumask_size());
713         if (mask == NULL) {
714                 CERROR("Failed to allocate scratch cpumask\n");
715                 goto failed;
716         }
717
718         for_each_online_node(i) {
719                 cpumask_copy(mask, cpumask_of_node(i));
720
721                 while (!cpumask_empty(mask)) {
722                         struct cfs_cpu_partition *part;
723                         int    n;
724
725                         /* Each emulated NUMA node has all allowed CPUs in
726                          * the mask.
727                          * End loop when all partitions have assigned CPUs.
728                          */
729                         if (cpt == ncpt)
730                                 break;
731
732                         part = &cptab->ctb_parts[cpt];
733
734                         n = num - cpumask_weight(part->cpt_cpumask);
735                         LASSERT(n > 0);
736
737                         rc = cfs_cpt_choose_ncpus(cptab, cpt, mask, n);
738                         if (rc < 0)
739                                 goto failed;
740
741                         LASSERT(num >= cpumask_weight(part->cpt_cpumask));
742                         if (num == cpumask_weight(part->cpt_cpumask))
743                                 cpt++;
744                 }
745         }
746
747         if (cpt != ncpt ||
748             num != cpumask_weight(cptab->ctb_parts[ncpt - 1].cpt_cpumask)) {
749                 CERROR("Expect %d(%d) CPU partitions but got %d(%d), "
750                        "CPU hotplug/unplug while setting?\n",
751                        cptab->ctb_nparts, num, cpt,
752                        cpumask_weight(cptab->ctb_parts[ncpt - 1].cpt_cpumask));
753                 goto failed;
754         }
755
756         LIBCFS_FREE(mask, cpumask_size());
757
758         return cptab;
759
760  failed:
761         CERROR("Failed to setup CPU-partition-table with %d "
762                "CPU-partitions, online HW nodes: %d, HW cpus: %d.\n",
763                ncpt, num_online_nodes(), num_online_cpus());
764
765         if (mask != NULL)
766                 LIBCFS_FREE(mask, cpumask_size());
767
768         if (cptab != NULL)
769                 cfs_cpt_table_free(cptab);
770
771         return NULL;
772 }
773
774 static struct cfs_cpt_table *
775 cfs_cpt_table_create_pattern(char *pattern)
776 {
777         struct cfs_cpt_table    *cptab;
778         char                    *str;
779         int                     node    = 0;
780         int                     ncpt    = 0;
781         int                     high;
782         int                     cpt;
783         int                     rc;
784         int                     c;
785         int                     i;
786
787         str = cfs_trimwhite(pattern);
788         if (*str == 'n' || *str == 'N') {
789                 pattern = str + 1;
790                 if (*pattern != '\0') {
791                         node = 1; /* numa pattern */
792
793                 } else { /* shortcut to create CPT from NUMA & CPU topology */
794                         node = -1;
795                         ncpt = num_online_nodes();
796                 }
797         }
798
799         if (ncpt == 0) { /* scanning bracket which is mark of partition */
800                 for (str = pattern;; str++, ncpt++) {
801                         str = strchr(str, '[');
802                         if (str == NULL)
803                                 break;
804                 }
805         }
806
807         if (ncpt == 0 ||
808             (node && ncpt > num_online_nodes()) ||
809             (!node && ncpt > num_online_cpus())) {
810                 CERROR("Invalid pattern %s, or too many partitions %d\n",
811                        pattern, ncpt);
812                 return NULL;
813         }
814
815         cptab = cfs_cpt_table_alloc(ncpt);
816         if (cptab == NULL) {
817                 CERROR("Failed to allocate cpu partition table\n");
818                 return NULL;
819         }
820
821         if (node < 0) { /* shortcut to create CPT from NUMA & CPU topology */
822                 cpt = 0;
823                 for_each_online_node(i) {
824                         if (cpt >= ncpt) {
825                                 CERROR("CPU changed while setting CPU "
826                                        "partition table, %d/%d\n", cpt, ncpt);
827                                 goto failed;
828                         }
829
830                         rc = cfs_cpt_set_node(cptab, cpt++, i);
831                         if (!rc)
832                                 goto failed;
833                 }
834                 return cptab;
835         }
836
837         high = node ? MAX_NUMNODES - 1 : nr_cpu_ids - 1;
838
839         for (str = cfs_trimwhite(pattern), c = 0;; c++) {
840                 struct cfs_range_expr   *range;
841                 struct cfs_expr_list    *el;
842                 char                    *bracket = strchr(str, '[');
843                 int                     n;
844
845                 if (bracket == NULL) {
846                         if (*str != 0) {
847                                 CERROR("Invalid pattern %s\n", str);
848                                 goto failed;
849                         } else if (c != ncpt) {
850                                 CERROR("expect %d partitions but found %d\n",
851                                        ncpt, c);
852                                 goto failed;
853                         }
854                         break;
855                 }
856
857                 if (sscanf(str, "%d%n", &cpt, &n) < 1) {
858                         CERROR("Invalid cpu pattern %s\n", str);
859                         goto failed;
860                 }
861
862                 if (cpt < 0 || cpt >= ncpt) {
863                         CERROR("Invalid partition id %d, total partitions %d\n",
864                                cpt, ncpt);
865                         goto failed;
866                 }
867
868                 if (cfs_cpt_weight(cptab, cpt) != 0) {
869                         CERROR("Partition %d has already been set.\n", cpt);
870                         goto failed;
871                 }
872
873                 str = cfs_trimwhite(str + n);
874                 if (str != bracket) {
875                         CERROR("Invalid pattern %s\n", str);
876                         goto failed;
877                 }
878
879                 bracket = strchr(str, ']');
880                 if (bracket == NULL) {
881                         CERROR("missing right bracket for cpt %d, %s\n",
882                                cpt, str);
883                         goto failed;
884                 }
885
886                 if (cfs_expr_list_parse(str, (bracket - str) + 1,
887                                         0, high, &el) != 0) {
888                         CERROR("Can't parse number range: %s\n", str);
889                         goto failed;
890                 }
891
892                 list_for_each_entry(range, &el->el_exprs, re_link) {
893                         for (i = range->re_lo; i <= range->re_hi; i++) {
894                                 if ((i - range->re_lo) % range->re_stride != 0)
895                                         continue;
896
897                                 rc = node ? cfs_cpt_set_node(cptab, cpt, i) :
898                                             cfs_cpt_set_cpu(cptab, cpt, i);
899                                 if (!rc) {
900                                         cfs_expr_list_free(el);
901                                         goto failed;
902                                 }
903                         }
904                 }
905
906                 cfs_expr_list_free(el);
907
908                 if (!cfs_cpt_online(cptab, cpt)) {
909                         CERROR("No online CPU is found on partition %d\n", cpt);
910                         goto failed;
911                 }
912
913                 str = cfs_trimwhite(bracket + 1);
914         }
915
916         return cptab;
917
918  failed:
919         cfs_cpt_table_free(cptab);
920         return NULL;
921 }
922
923 #ifdef CONFIG_HOTPLUG_CPU
924 static int
925 cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
926 {
927         unsigned int cpu = (unsigned long)hcpu;
928         bool         warn;
929
930         switch (action) {
931         case CPU_DEAD:
932         case CPU_DEAD_FROZEN:
933         case CPU_ONLINE:
934         case CPU_ONLINE_FROZEN:
935         default:
936                 if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) {
937                         CDEBUG(D_INFO, "CPU changed [cpu %u action %lx]\n",
938                                cpu, action);
939                         break;
940                 }
941
942                 /* if all HTs in a core are offline, it may break affinity */
943                 warn = cpumask_any_and(topology_sibling_cpumask(cpu),
944                                        cpu_online_mask) >= nr_cpu_ids;
945                 CDEBUG(warn ? D_WARNING : D_INFO,
946                        "Lustre: can't support CPU plug-out well now, "
947                        "performance and stability could be impacted"
948                        "[CPU %u action: %lx]\n", cpu, action);
949         }
950
951         return NOTIFY_OK;
952 }
953
954 static struct notifier_block cfs_cpu_notifier = {
955         .notifier_call  = cfs_cpu_notify,
956         .priority       = 0
957 };
958
959 #endif
960
961 void
962 cfs_cpu_fini(void)
963 {
964         if (cfs_cpt_table != NULL)
965                 cfs_cpt_table_free(cfs_cpt_table);
966
967 #ifdef CONFIG_HOTPLUG_CPU
968         unregister_hotcpu_notifier(&cfs_cpu_notifier);
969 #endif
970 }
971
972 int
973 cfs_cpu_init(void)
974 {
975         LASSERT(cfs_cpt_table == NULL);
976
977 #ifdef CONFIG_HOTPLUG_CPU
978         register_hotcpu_notifier(&cfs_cpu_notifier);
979 #endif
980         get_online_cpus();
981         if (*cpu_pattern != 0) {
982                 char *cpu_pattern_dup = kstrdup(cpu_pattern, GFP_KERNEL);
983
984                 if (cpu_pattern_dup == NULL) {
985                         CERROR("Failed to duplicate cpu_pattern\n");
986                         goto failed;
987                 }
988
989                 cfs_cpt_table = cfs_cpt_table_create_pattern(cpu_pattern_dup);
990                 kfree(cpu_pattern_dup);
991                 if (cfs_cpt_table == NULL) {
992                         CERROR("Failed to create cptab from pattern %s\n",
993                                cpu_pattern);
994                         goto failed;
995                 }
996
997         } else {
998                 cfs_cpt_table = cfs_cpt_table_create(cpu_npartitions);
999                 if (cfs_cpt_table == NULL) {
1000                         CERROR("Failed to create ptable with npartitions %d\n",
1001                                cpu_npartitions);
1002                         goto failed;
1003                 }
1004         }
1005         put_online_cpus();
1006
1007         LCONSOLE(0, "HW nodes: %d, HW CPU cores: %d, npartitions: %d\n",
1008                      num_online_nodes(), num_online_cpus(),
1009                      cfs_cpt_number(cfs_cpt_table));
1010         return 0;
1011
1012 failed:
1013         put_online_cpus();
1014         cfs_cpu_fini();
1015         return -1;
1016 }
1017
1018 #endif