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