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 * Copyright (c) 2012, Intel Corporation.
21 */
22 /*
23 * This file is part of Lustre, http://www.lustre.org/
24 * Lustre is a trademark of Sun Microsystems, Inc.
25 *
26 * Author: liang@whamcloud.com
27 */
28
29 #define DEBUG_SUBSYSTEM S_LNET
30
31 #include "../../include/linux/libcfs/libcfs.h"
32
33 struct cfs_var_array {
34 unsigned int va_count; /* # of buffers */
35 unsigned int va_size; /* size of each var */
36 struct cfs_cpt_table *va_cptab; /* cpu partition table */
37 void *va_ptrs[0]; /* buffer addresses */
38 };
39
40 /*
41 * free per-cpu data, see more detail in cfs_percpt_free
42 */
43 void
cfs_percpt_free(void * vars)44 cfs_percpt_free(void *vars)
45 {
46 struct cfs_var_array *arr;
47 int i;
48
49 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
50
51 for (i = 0; i < arr->va_count; i++) {
52 if (arr->va_ptrs[i])
53 LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
54 }
55
56 LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
57 va_ptrs[arr->va_count]));
58 }
59 EXPORT_SYMBOL(cfs_percpt_free);
60
61 /*
62 * allocate per cpu-partition variables, returned value is an array of pointers,
63 * variable can be indexed by CPU partition ID, i.e:
64 *
65 * arr = cfs_percpt_alloc(cfs_cpu_pt, size);
66 * then caller can access memory block for CPU 0 by arr[0],
67 * memory block for CPU 1 by arr[1]...
68 * memory block for CPU N by arr[N]...
69 *
70 * cacheline aligned.
71 */
72 void *
cfs_percpt_alloc(struct cfs_cpt_table * cptab,unsigned int size)73 cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size)
74 {
75 struct cfs_var_array *arr;
76 int count;
77 int i;
78
79 count = cfs_cpt_number(cptab);
80
81 LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
82 if (!arr)
83 return NULL;
84
85 size = L1_CACHE_ALIGN(size);
86 arr->va_size = size;
87 arr->va_count = count;
88 arr->va_cptab = cptab;
89
90 for (i = 0; i < count; i++) {
91 LIBCFS_CPT_ALLOC(arr->va_ptrs[i], cptab, i, size);
92 if (!arr->va_ptrs[i]) {
93 cfs_percpt_free((void *)&arr->va_ptrs[0]);
94 return NULL;
95 }
96 }
97
98 return (void *)&arr->va_ptrs[0];
99 }
100 EXPORT_SYMBOL(cfs_percpt_alloc);
101
102 /*
103 * return number of CPUs (or number of elements in per-cpu data)
104 * according to cptab of @vars
105 */
106 int
cfs_percpt_number(void * vars)107 cfs_percpt_number(void *vars)
108 {
109 struct cfs_var_array *arr;
110
111 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
112
113 return arr->va_count;
114 }
115 EXPORT_SYMBOL(cfs_percpt_number);
116
117 /*
118 * free variable array, see more detail in cfs_array_alloc
119 */
120 void
cfs_array_free(void * vars)121 cfs_array_free(void *vars)
122 {
123 struct cfs_var_array *arr;
124 int i;
125
126 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
127
128 for (i = 0; i < arr->va_count; i++) {
129 if (!arr->va_ptrs[i])
130 continue;
131
132 LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
133 }
134 LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
135 va_ptrs[arr->va_count]));
136 }
137 EXPORT_SYMBOL(cfs_array_free);
138
139 /*
140 * allocate a variable array, returned value is an array of pointers.
141 * Caller can specify length of array by @count, @size is size of each
142 * memory block in array.
143 */
144 void *
cfs_array_alloc(int count,unsigned int size)145 cfs_array_alloc(int count, unsigned int size)
146 {
147 struct cfs_var_array *arr;
148 int i;
149
150 LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
151 if (!arr)
152 return NULL;
153
154 arr->va_count = count;
155 arr->va_size = size;
156
157 for (i = 0; i < count; i++) {
158 LIBCFS_ALLOC(arr->va_ptrs[i], size);
159
160 if (!arr->va_ptrs[i]) {
161 cfs_array_free((void *)&arr->va_ptrs[0]);
162 return NULL;
163 }
164 }
165
166 return (void *)&arr->va_ptrs[0];
167 }
168 EXPORT_SYMBOL(cfs_array_alloc);
169