Whamcloud - gitweb
LU-9859 libcfs: switch to cpumask_var_t
[fs/lustre-release.git] / libcfs / include / libcfs / libcfs_cpu.h
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  * GPL HEADER END
17  */
18 /*
19  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
20  *
21  * Copyright (c) 2012, 2017, Intel Corporation.
22  */
23 /*
24  * This file is part of Lustre, http://www.lustre.org/
25  * Lustre is a trademark of Sun Microsystems, Inc.
26  *
27  * libcfs/include/libcfs/libcfs_cpu.h
28  *
29  * CPU partition
30  *   . CPU partition is virtual processing unit
31  *
32  *   . CPU partition can present 1-N cores, or 1-N NUMA nodes,
33  *     in other words, CPU partition is a processors pool.
34  *
35  * CPU Partition Table (CPT)
36  *   . a set of CPU partitions
37  *
38  *   . There are two modes for CPT: CFS_CPU_MODE_NUMA and CFS_CPU_MODE_SMP
39  *
40  *   . User can specify total number of CPU partitions while creating a
41  *     CPT, ID of CPU partition is always start from 0.
42  *
43  *     Example: if there are 8 cores on the system, while creating a CPT
44  *     with cpu_npartitions=4:
45  *              core[0, 1] = partition[0], core[2, 3] = partition[1]
46  *              core[4, 5] = partition[2], core[6, 7] = partition[3]
47  *
48  *          cpu_npartitions=1:
49  *              core[0, 1, ... 7] = partition[0]
50  *
51  *   . User can also specify CPU partitions by string pattern
52  *
53  *     Examples: cpu_partitions="0[0,1], 1[2,3]"
54  *               cpu_partitions="N 0[0-3], 1[4-8]"
55  *
56  *     The first character "N" means following numbers are numa ID
57  *
58  *   . NUMA allocators, CPU affinity threads are built over CPU partitions,
59  *     instead of HW CPUs or HW nodes.
60  *
61  *   . By default, Lustre modules should refer to the global cfs_cpt_table,
62  *     instead of accessing HW CPUs directly, so concurrency of Lustre can be
63  *     configured by cpu_npartitions of the global cfs_cpt_table
64  *
65  *   . If cpu_npartitions=1(all CPUs in one pool), lustre should work the
66  *     same way as 2.2 or earlier versions
67  *
68  * Author: liang@whamcloud.com
69  */
70
71 #ifndef __LIBCFS_CPU_H__
72 #define __LIBCFS_CPU_H__
73
74 #include <linux/cpu.h>
75 #include <linux/cpuset.h>
76 #include <linux/slab.h>
77 #include <linux/topology.h>
78 #include <linux/version.h>
79 #include <linux/vmalloc.h>
80
81 #include <libcfs/linux/linux-cpu.h>
82
83 #ifdef CONFIG_SMP
84
85 /** virtual processing unit */
86 struct cfs_cpu_partition {
87         /* CPUs mask for this partition */
88         cpumask_var_t                    cpt_cpumask;
89         /* nodes mask for this partition */
90         nodemask_t                      *cpt_nodemask;
91         /* NUMA distance between CPTs */
92         unsigned int                    *cpt_distance;
93         /* spread rotor for NUMA allocator */
94         int                              cpt_spread_rotor;
95         /* NUMA node if cpt_nodemask is empty */
96         int                              cpt_node;
97 };
98 #endif /* CONFIG_SMP */
99
100 /** descriptor for CPU partitions */
101 struct cfs_cpt_table {
102 #ifdef CONFIG_SMP
103         /* spread rotor for NUMA allocator */
104         int                              ctb_spread_rotor;
105         /* maximum NUMA distance between all nodes in table */
106         unsigned int                     ctb_distance;
107         /* partitions tables */
108         struct cfs_cpu_partition        *ctb_parts;
109         /* shadow HW CPU to CPU partition ID */
110         int                             *ctb_cpu2cpt;
111         /* shadow HW node to CPU partition ID */
112         int                             *ctb_node2cpt;
113         /* # of CPU partitions */
114         int                              ctb_nparts;
115         /* all nodes in this partition table */
116         nodemask_t                      *ctb_nodemask;
117 #else
118         nodemask_t                       ctb_nodemask;
119 #endif /* CONFIG_SMP */
120         /* all cpus in this partition table */
121         cpumask_var_t                    ctb_cpumask;
122 };
123
124 /* any CPU partition */
125 #define CFS_CPT_ANY             (-1)
126
127 extern struct cfs_cpt_table     *cfs_cpt_table;
128
129 /**
130  * destroy a CPU partition table
131  */
132 void cfs_cpt_table_free(struct cfs_cpt_table *cptab);
133 /**
134  * create a cfs_cpt_table with \a ncpt number of partitions
135  */
136 struct cfs_cpt_table *cfs_cpt_table_alloc(int ncpt);
137 /**
138  * print string information of cpt-table
139  */
140 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
141 /**
142  * print distance information of cpt-table
143  */
144 int cfs_cpt_distance_print(struct cfs_cpt_table *cptab, char *buf, int len);
145 /**
146  * return total number of CPU partitions in \a cptab
147  */
148 int cfs_cpt_number(struct cfs_cpt_table *cptab);
149 /**
150  * return number of HW cores or hyper-threadings in a CPU partition \a cpt
151  */
152 int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt);
153 /**
154  * is there any online CPU in CPU partition \a cpt
155  */
156 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
157 /**
158  * return cpumask of CPU partition \a cpt
159  */
160 cpumask_var_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
161 /**
162  * return nodemask of CPU partition \a cpt
163  */
164 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
165 /**
166  * shadow current HW processor ID to CPU-partition ID of \a cptab
167  */
168 int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap);
169 /**
170  * shadow HW processor ID \a CPU to CPU-partition ID by \a cptab
171  */
172 int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu);
173 /**
174  * shadow HW node ID \a NODE to CPU-partition ID by \a cptab
175  */
176 int cfs_cpt_of_node(struct cfs_cpt_table *cptab, int node);
177 /**
178  * NUMA distance between \a cpt1 and \a cpt2 in \a cptab
179  */
180 unsigned int cfs_cpt_distance(struct cfs_cpt_table *cptab, int cpt1, int cpt2);
181 /**
182  * bind current thread on a CPU-partition \a cpt of \a cptab
183  */
184 int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt);
185 /**
186  * add \a cpu to CPU partition @cpt of \a cptab, return 1 for success,
187  * otherwise 0 is returned
188  */
189 int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
190 /**
191  * remove \a cpu from CPU partition \a cpt of \a cptab
192  */
193 void cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
194 /**
195  * add all cpus in \a mask to CPU partition \a cpt
196  * return 1 if successfully set all CPUs, otherwise return 0
197  */
198 int cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab, int cpt,
199                         const cpumask_t *mask);
200 /**
201  * remove all cpus in \a mask from CPU partition \a cpt
202  */
203 void cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab, int cpt,
204                            const cpumask_t *mask);
205 /**
206  * add all cpus in NUMA node \a node to CPU partition \a cpt
207  * return 1 if successfully set all CPUs, otherwise return 0
208  */
209 int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node);
210 /**
211  * remove all cpus in NUMA node \a node from CPU partition \a cpt
212  */
213 void cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node);
214
215 /**
216  * add all cpus in node mask \a mask to CPU partition \a cpt
217  * return 1 if successfully set all CPUs, otherwise return 0
218  */
219 int cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab, int cpt,
220                          const nodemask_t *mask);
221 /**
222  * remove all cpus in node mask \a mask from CPU partition \a cpt
223  */
224 void cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab, int cpt,
225                             const nodemask_t *mask);
226 /**
227  * convert partition id \a cpt to numa node id, if there are more than one
228  * nodes in this partition, it might return a different node id each time.
229  */
230 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt);
231
232 /*
233  * allocate per-cpu-partition data, returned value is an array of pointers,
234  * variable can be indexed by CPU ID.
235  *      cptab != NULL: size of array is number of CPU partitions
236  *      cptab == NULL: size of array is number of HW cores
237  */
238 void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
239 /*
240  * destroy per-cpu-partition variable
241  */
242 void cfs_percpt_free(void *vars);
243 int cfs_percpt_number(void *vars);
244
245 #define cfs_percpt_for_each(var, i, vars)               \
246         for (i = 0; i < cfs_percpt_number(vars) &&      \
247                 ((var) = (vars)[i]) != NULL; i++)
248
249 /*
250  * percpu partition lock
251  *
252  * There are some use-cases like this in Lustre:
253  * . each CPU partition has it's own private data which is frequently changed,
254  *   and mostly by the local CPU partition.
255  * . all CPU partitions share some global data, these data are rarely changed.
256  *
257  * LNet is typical example.
258  * CPU partition lock is designed for this kind of use-cases:
259  * . each CPU partition has it's own private lock
260  * . change on private data just needs to take the private lock
261  * . read on shared data just needs to take _any_ of private locks
262  * . change on shared data needs to take _all_ private locks,
263  *   which is slow and should be really rare.
264  */
265 enum {
266         CFS_PERCPT_LOCK_EX      = -1,   /* negative */
267 };
268
269 struct cfs_percpt_lock {
270         /* cpu-partition-table for this lock */
271         struct cfs_cpt_table     *pcl_cptab;
272         /* exclusively locked */
273         unsigned int              pcl_locked;
274         /* private lock table */
275         spinlock_t              **pcl_locks;
276 };
277
278 /* return number of private locks */
279 #define cfs_percpt_lock_num(pcl)        cfs_cpt_number(pcl->pcl_cptab)
280
281 /*
282  * create a cpu-partition lock based on CPU partition table \a cptab,
283  * each private lock has extra \a psize bytes padding data
284  */
285 struct cfs_percpt_lock *cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
286                                                struct lock_class_key *keys);
287 /* destroy a cpu-partition lock */
288 void cfs_percpt_lock_free(struct cfs_percpt_lock *pcl);
289
290 /* lock private lock \a index of \a pcl */
291 void cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index);
292
293 /* unlock private lock \a index of \a pcl */
294 void cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index);
295
296 #define CFS_PERCPT_LOCK_KEYS    256
297
298 /* NB: don't allocate keys dynamically, lockdep needs them to be in ".data" */
299 #define cfs_percpt_lock_alloc(cptab)                                    \
300 ({                                                                      \
301         static struct lock_class_key ___keys[CFS_PERCPT_LOCK_KEYS];     \
302         struct cfs_percpt_lock *___lk;                                  \
303                                                                         \
304         if (cfs_cpt_number(cptab) > CFS_PERCPT_LOCK_KEYS)               \
305                 ___lk = cfs_percpt_lock_create(cptab, NULL);            \
306         else                                                            \
307                 ___lk = cfs_percpt_lock_create(cptab, ___keys);         \
308         ___lk;                                                          \
309 })
310
311 /**
312  * allocate \a nr_bytes of physical memory from a contiguous region with the
313  * properties of \a flags which are bound to the partition id \a cpt. This
314  * function should only be used for the case when only a few pages of memory
315  * are need.
316  */
317 static inline void *
318 cfs_cpt_malloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes,
319                gfp_t flags)
320 {
321         return kmalloc_node(nr_bytes, flags,
322                             cfs_cpt_spread_node(cptab, cpt));
323 }
324
325 /**
326  * allocate \a nr_bytes of virtually contiguous memory that is bound to the
327  * partition id \a cpt.
328  */
329 static inline void *
330 cfs_cpt_vzalloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes)
331 {
332         /* vzalloc_node() sets __GFP_FS by default but no current Kernel
333          * exported entry-point allows for both a NUMA node specification
334          * and a custom allocation flags mask. This may be an issue since
335          * __GFP_FS usage can cause some deadlock situations in our code,
336          * like when memory reclaim started, within the same context of a
337          * thread doing FS operations, that can also attempt conflicting FS
338          * operations, ...
339          */
340         return vzalloc_node(nr_bytes, cfs_cpt_spread_node(cptab, cpt));
341 }
342
343 /**
344  * allocate a single page of memory with the properties of \a flags were
345  * that page is bound to the partition id \a cpt.
346  */
347 static inline struct page *
348 cfs_page_cpt_alloc(struct cfs_cpt_table *cptab, int cpt, gfp_t flags)
349 {
350         return alloc_pages_node(cfs_cpt_spread_node(cptab, cpt), flags, 0);
351 }
352
353 /**
354  * allocate a chunck of memory from a memory pool that is bound to the
355  * partition id \a cpt with the properites of \a flags.
356  */
357 static inline void *
358 cfs_mem_cache_cpt_alloc(struct kmem_cache *cachep, struct cfs_cpt_table *cptab,
359                         int cpt, gfp_t flags)
360 {
361         return kmem_cache_alloc_node(cachep, flags,
362                                      cfs_cpt_spread_node(cptab, cpt));
363 }
364
365 /**
366  * iterate over all CPU partitions in \a cptab
367  */
368 #define cfs_cpt_for_each(i, cptab)      \
369         for (i = 0; i < cfs_cpt_number(cptab); i++)
370
371 int  cfs_cpu_init(void);
372 void cfs_cpu_fini(void);
373
374 #endif /* __LIBCFS_CPU_H__ */