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