• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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