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