Whamcloud - gitweb
3e83f50579913e9105448e11a43ddf0fbd6d0c69
[fs/lustre-release.git] / libcfs / libcfs / libcfs_mem.c
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 <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
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 *
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
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  * free variable array, see more detail in cfs_array_alloc
123  */
124 void
125 cfs_array_free(void *vars)
126 {
127         struct cfs_var_array    *arr;
128         int                     i;
129
130         arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
131
132         for (i = 0; i < arr->va_count; i++) {
133                 if (arr->va_ptrs[i] == NULL)
134                         continue;
135
136                 LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
137         }
138         LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
139                                   va_ptrs[arr->va_count]));
140 }
141 EXPORT_SYMBOL(cfs_array_free);
142
143 /*
144  * allocate a variable array, returned value is an array of pointers.
145  * Caller can specify length of array by @count, @size is size of each
146  * memory block in array.
147  */
148 void *
149 cfs_array_alloc(int count, unsigned int size)
150 {
151         struct cfs_var_array    *arr;
152         int                     i;
153
154         LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
155         if (arr == NULL)
156                 return NULL;
157
158         arr->va_count   = count;
159         arr->va_size    = size;
160
161         for (i = 0; i < count; i++) {
162                 LIBCFS_ALLOC(arr->va_ptrs[i], size);
163
164                 if (arr->va_ptrs[i] == NULL) {
165                         cfs_array_free((void *)&arr->va_ptrs[0]);
166                         return NULL;
167                 }
168         }
169
170         return (void *)&arr->va_ptrs[0];
171 }
172 EXPORT_SYMBOL(cfs_array_alloc);