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