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 "../../include/linux/libcfs/libcfs.h"
37
38 struct cfs_var_array {
39 unsigned int va_count; /* # of buffers */
40 unsigned int va_size; /* size of each var */
41 struct cfs_cpt_table *va_cptab; /* cpu partition table */
42 void *va_ptrs[0]; /* buffer addresses */
43 };
44
45 /*
46 * free per-cpu data, see more detail in cfs_percpt_free
47 */
48 void
cfs_percpt_free(void * vars)49 cfs_percpt_free(void *vars)
50 {
51 struct cfs_var_array *arr;
52 int i;
53
54 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
55
56 for (i = 0; i < arr->va_count; i++) {
57 if (arr->va_ptrs[i] != NULL)
58 LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
59 }
60
61 LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
62 va_ptrs[arr->va_count]));
63 }
64 EXPORT_SYMBOL(cfs_percpt_free);
65
66 /*
67 * allocate per cpu-partition variables, returned value is an array of pointers,
68 * variable can be indexed by CPU partition ID, i.e:
69 *
70 * arr = cfs_percpt_alloc(cfs_cpu_pt, size);
71 * then caller can access memory block for CPU 0 by arr[0],
72 * memory block for CPU 1 by arr[1]...
73 * memory block for CPU N by arr[N]...
74 *
75 * cacheline aligned.
76 */
77 void *
cfs_percpt_alloc(struct cfs_cpt_table * cptab,unsigned int size)78 cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size)
79 {
80 struct cfs_var_array *arr;
81 int count;
82 int i;
83
84 count = cfs_cpt_number(cptab);
85
86 LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
87 if (arr == NULL)
88 return NULL;
89
90 arr->va_size = size = L1_CACHE_ALIGN(size);
91 arr->va_count = count;
92 arr->va_cptab = cptab;
93
94 for (i = 0; i < count; i++) {
95 LIBCFS_CPT_ALLOC(arr->va_ptrs[i], cptab, i, size);
96 if (arr->va_ptrs[i] == NULL) {
97 cfs_percpt_free((void *)&arr->va_ptrs[0]);
98 return NULL;
99 }
100 }
101
102 return (void *)&arr->va_ptrs[0];
103 }
104 EXPORT_SYMBOL(cfs_percpt_alloc);
105
106 /*
107 * return number of CPUs (or number of elements in per-cpu data)
108 * according to cptab of @vars
109 */
110 int
cfs_percpt_number(void * vars)111 cfs_percpt_number(void *vars)
112 {
113 struct cfs_var_array *arr;
114
115 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
116
117 return arr->va_count;
118 }
119 EXPORT_SYMBOL(cfs_percpt_number);
120
121 /*
122 * return memory block shadowed from current CPU
123 */
124 void *
cfs_percpt_current(void * vars)125 cfs_percpt_current(void *vars)
126 {
127 struct cfs_var_array *arr;
128 int cpt;
129
130 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
131 cpt = cfs_cpt_current(arr->va_cptab, 0);
132 if (cpt < 0)
133 return NULL;
134
135 return arr->va_ptrs[cpt];
136 }
137 EXPORT_SYMBOL(cfs_percpt_current);
138
139 void *
cfs_percpt_index(void * vars,int idx)140 cfs_percpt_index(void *vars, int idx)
141 {
142 struct cfs_var_array *arr;
143
144 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
145
146 LASSERT(idx >= 0 && idx < arr->va_count);
147 return arr->va_ptrs[idx];
148 }
149 EXPORT_SYMBOL(cfs_percpt_index);
150
151 /*
152 * free variable array, see more detail in cfs_array_alloc
153 */
154 void
cfs_array_free(void * vars)155 cfs_array_free(void *vars)
156 {
157 struct cfs_var_array *arr;
158 int i;
159
160 arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
161
162 for (i = 0; i < arr->va_count; i++) {
163 if (arr->va_ptrs[i] == NULL)
164 continue;
165
166 LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
167 }
168 LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
169 va_ptrs[arr->va_count]));
170 }
171 EXPORT_SYMBOL(cfs_array_free);
172
173 /*
174 * allocate a variable array, returned value is an array of pointers.
175 * Caller can specify length of array by @count, @size is size of each
176 * memory block in array.
177 */
178 void *
cfs_array_alloc(int count,unsigned int size)179 cfs_array_alloc(int count, unsigned int size)
180 {
181 struct cfs_var_array *arr;
182 int i;
183
184 LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
185 if (arr == NULL)
186 return NULL;
187
188 arr->va_count = count;
189 arr->va_size = size;
190
191 for (i = 0; i < count; i++) {
192 LIBCFS_ALLOC(arr->va_ptrs[i], size);
193
194 if (arr->va_ptrs[i] == NULL) {
195 cfs_array_free((void *)&arr->va_ptrs[0]);
196 return NULL;
197 }
198 }
199
200 return (void *)&arr->va_ptrs[0];
201 }
202 EXPORT_SYMBOL(cfs_array_alloc);
203