Whamcloud - gitweb
6bf0af595a018dfe8d578e459ca595fa09e0492d
[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, 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 #ifdef HAVE_SET_MEMS_ALLOWED
660                 set_mems_allowed(*nodemask);
661 #endif
662                 if (rc == 0)
663                         cfs_schedule(); /* switch to allowed CPU */
664
665                 return rc;
666         }
667
668         /* don't need to set affinity because all online CPUs are covered */
669         return 0;
670 }
671 EXPORT_SYMBOL(cfs_cpt_bind);
672
673 /**
674  * Choose max to \a number CPUs from \a node and set them in \a cpt.
675  * We always prefer to choose CPU in the same core/socket.
676  */
677 static int
678 cfs_cpt_choose_ncpus(struct cfs_cpt_table *cptab, int cpt,
679                      cpumask_t *node, int number)
680 {
681         cpumask_t       *socket = NULL;
682         cpumask_t       *core = NULL;
683         int             rc = 0;
684         int             cpu;
685
686         LASSERT(number > 0);
687
688         if (number >= cpus_weight(*node)) {
689                 while (!cpus_empty(*node)) {
690                         cpu = first_cpu(*node);
691
692                         rc = cfs_cpt_set_cpu(cptab, cpt, cpu);
693                         if (!rc)
694                                 return -EINVAL;
695                         cpu_clear(cpu, *node);
696                 }
697                 return 0;
698         }
699
700         /* allocate scratch buffer */
701         LIBCFS_ALLOC(socket, cpumask_size());
702         LIBCFS_ALLOC(core, cpumask_size());
703         if (socket == NULL || core == NULL) {
704                 rc = -ENOMEM;
705                 goto out;
706         }
707
708         while (!cpus_empty(*node)) {
709                 cpu = first_cpu(*node);
710
711                 /* get cpumask for cores in the same socket */
712                 cfs_cpu_core_siblings(cpu, socket);
713                 cpus_and(*socket, *socket, *node);
714
715                 LASSERT(!cpus_empty(*socket));
716
717                 while (!cpus_empty(*socket)) {
718                         int     i;
719
720                         /* get cpumask for hts in the same core */
721                         cfs_cpu_ht_siblings(cpu, core);
722                         cpus_and(*core, *core, *node);
723
724                         LASSERT(!cpus_empty(*core));
725
726                         for_each_cpu_mask(i, *core) {
727                                 cpu_clear(i, *socket);
728                                 cpu_clear(i, *node);
729
730                                 rc = cfs_cpt_set_cpu(cptab, cpt, i);
731                                 if (!rc) {
732                                         rc = -EINVAL;
733                                         goto out;
734                                 }
735
736                                 if (--number == 0)
737                                         goto out;
738                         }
739                         cpu = first_cpu(*socket);
740                 }
741         }
742
743  out:
744         if (socket != NULL)
745                 LIBCFS_FREE(socket, cpumask_size());
746         if (core != NULL)
747                 LIBCFS_FREE(core, cpumask_size());
748         return rc;
749 }
750
751 #define CPT_WEIGHT_MIN  4u
752
753 static unsigned int
754 cfs_cpt_num_estimate(void)
755 {
756         unsigned nnode = num_online_nodes();
757         unsigned ncpu  = num_online_cpus();
758         unsigned ncpt;
759
760         if (ncpu <= CPT_WEIGHT_MIN) {
761                 ncpt = 1;
762                 goto out;
763         }
764
765         /* generate reasonable number of CPU partitions based on total number
766          * of CPUs, Preferred N should be power2 and match this condition:
767          * 2 * (N - 1)^2 < NCPUS <= 2 * N^2 */
768         for (ncpt = 2; ncpu > 2 * ncpt * ncpt; ncpt <<= 1) {}
769
770         if (ncpt <= nnode) { /* fat numa system */
771                 while (nnode > ncpt)
772                         nnode >>= 1;
773
774         } else { /* ncpt > nnode */
775                 while ((nnode << 1) <= ncpt)
776                         nnode <<= 1;
777         }
778
779         ncpt = nnode;
780
781  out:
782 #if (BITS_PER_LONG == 32)
783         /* config many CPU partitions on 32-bit system could consume
784          * too much memory */
785         ncpt = min(2U, ncpt);
786 #endif
787         while (ncpu % ncpt != 0)
788                 ncpt--; /* worst case is 1 */
789
790         return ncpt;
791 }
792
793 static struct cfs_cpt_table *
794 cfs_cpt_table_create(int ncpt)
795 {
796         struct cfs_cpt_table *cptab = NULL;
797         cpumask_t       *mask = NULL;
798         int             cpt = 0;
799         int             num;
800         int             rc;
801         int             i;
802
803         rc = cfs_cpt_num_estimate();
804         if (ncpt <= 0)
805                 ncpt = rc;
806
807         if (ncpt > num_online_cpus() || ncpt > 4 * rc) {
808                 CWARN("CPU partition number %d is larger than suggested "
809                       "value (%d), your system may have performance"
810                       "issue or run out of memory while under pressure\n",
811                       ncpt, rc);
812         }
813
814         if (num_online_cpus() % ncpt != 0) {
815                 CERROR("CPU number %d is not multiple of cpu_npartition %d, "
816                        "please try different cpu_npartitions value or"
817                        "set pattern string by cpu_pattern=STRING\n",
818                        (int)num_online_cpus(), ncpt);
819                 goto failed;
820         }
821
822         cptab = cfs_cpt_table_alloc(ncpt);
823         if (cptab == NULL) {
824                 CERROR("Failed to allocate CPU map(%d)\n", ncpt);
825                 goto failed;
826         }
827
828         num = num_online_cpus() / ncpt;
829         if (num == 0) {
830                 CERROR("CPU changed while setting CPU partition\n");
831                 goto failed;
832         }
833
834         LIBCFS_ALLOC(mask, cpumask_size());
835         if (mask == NULL) {
836                 CERROR("Failed to allocate scratch cpumask\n");
837                 goto failed;
838         }
839
840         for_each_online_node(i) {
841                 cfs_node_to_cpumask(i, mask);
842
843                 while (!cpus_empty(*mask)) {
844                         struct cfs_cpu_partition *part;
845                         int    n;
846
847                         if (cpt >= ncpt)
848                                 goto failed;
849
850                         part = &cptab->ctb_parts[cpt];
851
852                         n = num - cpus_weight(*part->cpt_cpumask);
853                         LASSERT(n > 0);
854
855                         rc = cfs_cpt_choose_ncpus(cptab, cpt, mask, n);
856                         if (rc < 0)
857                                 goto failed;
858
859                         LASSERT(num >= cpus_weight(*part->cpt_cpumask));
860                         if (num == cpus_weight(*part->cpt_cpumask))
861                                 cpt++;
862                 }
863         }
864
865         if (cpt != ncpt ||
866             num != cpus_weight(*cptab->ctb_parts[ncpt - 1].cpt_cpumask)) {
867                 CERROR("Expect %d(%d) CPU partitions but got %d(%d), "
868                        "CPU hotplug/unplug while setting?\n",
869                        cptab->ctb_nparts, num, cpt,
870                        cpus_weight(*cptab->ctb_parts[ncpt - 1].cpt_cpumask));
871                 goto failed;
872         }
873
874         LIBCFS_FREE(mask, cpumask_size());
875
876         return cptab;
877
878  failed:
879         CERROR("Failed to setup CPU-partition-table with %d "
880                "CPU-partitions, online HW nodes: %d, HW cpus: %d.\n",
881                ncpt, num_online_nodes(), num_online_cpus());
882
883         if (mask != NULL)
884                 LIBCFS_FREE(mask, cpumask_size());
885
886         if (cptab != NULL)
887                 cfs_cpt_table_free(cptab);
888
889         return NULL;
890 }
891
892 static struct cfs_cpt_table *
893 cfs_cpt_table_create_pattern(char *pattern)
894 {
895         struct cfs_cpt_table    *cptab;
896         char                    *str    = pattern;
897         int                     node    = 0;
898         int                     high;
899         int                     ncpt;
900         int                     c;
901
902         for (ncpt = 0;; ncpt++) { /* quick scan bracket */
903                 str = strchr(str, '[');
904                 if (str == NULL)
905                         break;
906                 str++;
907         }
908
909         str = cfs_trimwhite(pattern);
910         if (*str == 'n' || *str == 'N') {
911                 pattern = str + 1;
912                 node = 1;
913         }
914
915         if (ncpt == 0 ||
916             (node && ncpt > num_online_nodes()) ||
917             (!node && ncpt > num_online_cpus())) {
918                 CERROR("Invalid pattern %s, or too many partitions %d\n",
919                        pattern, ncpt);
920                 return NULL;
921         }
922
923         high = node ? MAX_NUMNODES - 1 : NR_CPUS - 1;
924
925         cptab = cfs_cpt_table_alloc(ncpt);
926         if (cptab == NULL) {
927                 CERROR("Failed to allocate cpu partition table\n");
928                 return NULL;
929         }
930
931         for (str = cfs_trimwhite(pattern), c = 0;; c++) {
932                 struct cfs_range_expr   *range;
933                 struct cfs_expr_list    *el;
934                 char                    *bracket = strchr(str, '[');
935                 int                     cpt;
936                 int                     rc;
937                 int                     i;
938                 int                     n;
939
940                 if (bracket == NULL) {
941                         if (*str != 0) {
942                                 CERROR("Invalid pattern %s\n", str);
943                                 goto failed;
944                         } else if (c != ncpt) {
945                                 CERROR("expect %d partitions but found %d\n",
946                                        ncpt, c);
947                                 goto failed;
948                         }
949                         break;
950                 }
951
952                 if (sscanf(str, "%u%n", &cpt, &n) < 1) {
953                         CERROR("Invalid cpu pattern %s\n", str);
954                         goto failed;
955                 }
956
957                 if (cpt < 0 || cpt >= ncpt) {
958                         CERROR("Invalid partition id %d, total partitions %d\n",
959                                cpt, ncpt);
960                         goto failed;
961                 }
962
963                 if (cfs_cpt_weight(cptab, cpt) != 0) {
964                         CERROR("Partition %d has already been set.\n", cpt);
965                         goto failed;
966                 }
967
968                 str = cfs_trimwhite(str + n);
969                 if (str != bracket) {
970                         CERROR("Invalid pattern %s\n", str);
971                         goto failed;
972                 }
973
974                 bracket = strchr(str, ']');
975                 if (bracket == NULL) {
976                         CERROR("missing right bracket for cpt %d, %s\n",
977                                cpt, str);
978                         goto failed;
979                 }
980
981                 if (cfs_expr_list_parse(str, (bracket - str) + 1,
982                                         0, high, &el) != 0) {
983                         CERROR("Can't parse number range: %s\n", str);
984                         goto failed;
985                 }
986
987                 cfs_list_for_each_entry(range, &el->el_exprs, re_link) {
988                         for (i = range->re_lo; i <= range->re_hi; i++) {
989                                 if ((i - range->re_lo) % range->re_stride != 0)
990                                         continue;
991
992                                 rc = node ? cfs_cpt_set_node(cptab, cpt, i) :
993                                             cfs_cpt_set_cpu(cptab, cpt, i);
994                                 if (!rc) {
995                                         cfs_expr_list_free(el);
996                                         goto failed;
997                                 }
998                         }
999                 }
1000
1001                 cfs_expr_list_free(el);
1002
1003                 if (!cfs_cpt_online(cptab, cpt)) {
1004                         CERROR("No online CPU is found on partition %d\n", cpt);
1005                         goto failed;
1006                 }
1007
1008                 str = cfs_trimwhite(bracket + 1);
1009         }
1010
1011         return cptab;
1012
1013  failed:
1014         cfs_cpt_table_free(cptab);
1015         return NULL;
1016 }
1017
1018 #ifdef CONFIG_HOTPLUG_CPU
1019 static int
1020 cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
1021 {
1022         unsigned int  cpu = (unsigned long)hcpu;
1023
1024         switch (action) {
1025         case CPU_DEAD:
1026         case CPU_DEAD_FROZEN:
1027         case CPU_ONLINE:
1028         case CPU_ONLINE_FROZEN:
1029                 spin_lock(&cpt_data.cpt_lock);
1030                 cpt_data.cpt_version++;
1031                 spin_unlock(&cpt_data.cpt_lock);
1032         default:
1033                 CWARN("Lustre: can't support CPU hotplug well now, "
1034                       "performance and stability could be impacted"
1035                       "[CPU %u notify: %lx]\n", cpu, action);
1036         }
1037
1038         return NOTIFY_OK;
1039 }
1040
1041 static struct notifier_block cfs_cpu_notifier = {
1042         .notifier_call  = cfs_cpu_notify,
1043         .priority       = 0
1044 };
1045
1046 #endif
1047
1048 void
1049 cfs_cpu_fini(void)
1050 {
1051         if (cfs_cpt_table != NULL)
1052                 cfs_cpt_table_free(cfs_cpt_table);
1053
1054 #ifdef CONFIG_HOTPLUG_CPU
1055         unregister_hotcpu_notifier(&cfs_cpu_notifier);
1056 #endif
1057         if (cpt_data.cpt_cpumask != NULL)
1058                 LIBCFS_FREE(cpt_data.cpt_cpumask, cpumask_size());
1059 }
1060
1061 int
1062 cfs_cpu_init(void)
1063 {
1064         LASSERT(cfs_cpt_table == NULL);
1065
1066         memset(&cpt_data, 0, sizeof(cpt_data));
1067
1068         LIBCFS_ALLOC(cpt_data.cpt_cpumask, cpumask_size());
1069         if (cpt_data.cpt_cpumask == NULL) {
1070                 CERROR("Failed to allocate scratch buffer\n");
1071                 return -1;
1072         }
1073
1074         spin_lock_init(&cpt_data.cpt_lock);
1075         sema_init(&cpt_data.cpt_mutex, 1);
1076
1077 #ifdef CONFIG_HOTPLUG_CPU
1078         register_hotcpu_notifier(&cfs_cpu_notifier);
1079 #endif
1080
1081         if (*cpu_pattern != 0) {
1082                 cfs_cpt_table = cfs_cpt_table_create_pattern(cpu_pattern);
1083                 if (cfs_cpt_table == NULL) {
1084                         CERROR("Failed to create cptab from pattern %s\n",
1085                                cpu_pattern);
1086                         goto failed;
1087                 }
1088
1089         } else {
1090                 cfs_cpt_table = cfs_cpt_table_create(cpu_npartitions);
1091                 if (cfs_cpt_table == NULL) {
1092                         CERROR("Failed to create ptable with npartitions %d\n",
1093                                cpu_npartitions);
1094                         goto failed;
1095                 }
1096         }
1097
1098         spin_lock(&cpt_data.cpt_lock);
1099         if (cfs_cpt_table->ctb_version != cpt_data.cpt_version) {
1100                 spin_unlock(&cpt_data.cpt_lock);
1101                 CERROR("CPU hotplug/unplug during setup\n");
1102                 goto failed;
1103         }
1104         spin_unlock(&cpt_data.cpt_lock);
1105
1106         LCONSOLE(0, "HW CPU cores: %d, npartitions: %d\n",
1107                  num_online_cpus(), cfs_cpt_number(cfs_cpt_table));
1108         return 0;
1109
1110  failed:
1111         cfs_cpu_fini();
1112         return -1;
1113 }
1114
1115 #endif