• 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  * 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