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