Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[fs/lustre-release.git] / libcfs / libcfs / libcfs_lock.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 /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011, 2012, Whamcloud, Inc.
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  * Lustre is a trademark of Sun Microsystems, Inc.
29  *
30  * Author: liang@whamcloud.com
31  */
32
33 #ifndef EXPORT_SYMTAB
34 # define EXPORT_SYMTAB
35 #endif
36 #define DEBUG_SUBSYSTEM S_LNET
37
38 #include <libcfs/libcfs.h>
39
40 #ifdef __KERNEL__
41
42 /** destroy cpu-partition lock, see libcfs_private.h for more detail */
43 void
44 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
45 {
46         LASSERT(pcl->pcl_locks != NULL);
47         LASSERT(!pcl->pcl_locked);
48
49         cfs_percpt_free(pcl->pcl_locks);
50         LIBCFS_FREE(pcl, sizeof(*pcl));
51 }
52 CFS_EXPORT_SYMBOL(cfs_percpt_lock_free);
53
54 /**
55  * create cpu-partition lock, see libcfs_private.h for more detail.
56  *
57  * cpu-partition lock is designed for large-scale SMP system, so we need to
58  * reduce cacheline conflict as possible as we can, that's the
59  * reason we always allocate cacheline-aligned memory block.
60  */
61 struct cfs_percpt_lock *
62 cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab)
63 {
64         struct cfs_percpt_lock  *pcl;
65         spinlock_t              *lock;
66         int                     i;
67
68         /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
69         LIBCFS_ALLOC(pcl, sizeof(*pcl));
70         if (pcl == NULL)
71                 return NULL;
72
73         pcl->pcl_cptab = cptab;
74         pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
75         if (pcl->pcl_locks == NULL) {
76                 LIBCFS_FREE(pcl, sizeof(*pcl));
77                 return NULL;
78         }
79
80         cfs_percpt_for_each(lock, i, pcl->pcl_locks)
81                 spin_lock_init(lock);
82
83         return pcl;
84 }
85 CFS_EXPORT_SYMBOL(cfs_percpt_lock_alloc);
86
87 /**
88  * lock a CPU partition
89  *
90  * \a index != CFS_PERCPT_LOCK_EX
91  *     hold private lock indexed by \a index
92  *
93  * \a index == CFS_PERCPT_LOCK_EX
94  *     exclusively lock @pcl and nobody can take private lock
95  */
96 void
97 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
98 {
99         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
100         int     i;
101
102         LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
103
104         if (ncpt == 1) {
105                 index = 0;
106         } else { /* serialize with exclusive lock */
107                 while (pcl->pcl_locked)
108                         cpu_relax();
109         }
110
111         if (likely(index != CFS_PERCPT_LOCK_EX)) {
112                 spin_lock(pcl->pcl_locks[index]);
113                 return;
114         }
115
116         /* exclusive lock request */
117         for (i = 0; i < ncpt; i++) {
118                 spin_lock(pcl->pcl_locks[i]);
119                 if (i == 0) {
120                         LASSERT(!pcl->pcl_locked);
121                         /* nobody should take private lock after this
122                          * so I wouldn't starve for too long time */
123                         pcl->pcl_locked = 1;
124                 }
125         }
126 }
127 CFS_EXPORT_SYMBOL(cfs_percpt_lock);
128
129 /** unlock a CPU partition */
130 void
131 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
132 {
133         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
134         int     i;
135
136         index = ncpt == 1 ? 0 : index;
137
138         if (likely(index != CFS_PERCPT_LOCK_EX)) {
139                 spin_unlock(pcl->pcl_locks[index]);
140                 return;
141         }
142
143         for (i = ncpt - 1; i >= 0; i--) {
144                 if (i == 0) {
145                         LASSERT(pcl->pcl_locked);
146                         pcl->pcl_locked = 0;
147                 }
148                 spin_unlock(pcl->pcl_locks[i]);
149         }
150 }
151 CFS_EXPORT_SYMBOL(cfs_percpt_unlock);
152
153 #else /* !__KERNEL__ */
154 # ifdef HAVE_LIBPTHREAD
155
156 struct cfs_percpt_lock *
157 cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab)
158 {
159         struct cfs_percpt_lock *pcl;
160
161         CFS_ALLOC_PTR(pcl);
162         if (pcl != NULL)
163                 pthread_mutex_init(&pcl->pcl_mutex, NULL);
164
165         return pcl;
166 }
167
168 void
169 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
170 {
171         pthread_mutex_destroy(&pcl->pcl_mutex);
172         CFS_FREE_PTR(pcl);
173 }
174
175 void
176 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int lock)
177 {
178         pthread_mutex_lock(&(pcl)->pcl_mutex);
179 }
180
181 void
182 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int lock)
183 {
184         pthread_mutex_unlock(&(pcl)->pcl_mutex);
185 }
186
187 # else /* !HAVE_LIBPTHREAD */
188
189 struct cfs_percpt_lock *
190 cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab)
191 {
192         return ((struct cfs_percpt_lock *) &CFS_PERCPT_LOCK_MAGIC);
193 }
194
195 void
196 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
197 {
198         LASSERT(pcl == (struct cfs_percpt_lock *) &CFS_PERCPT_LOCK_MAGIC);
199 }
200
201 void
202 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
203 {
204         LASSERT(pcl == (struct cfs_percpt_lock *) &CFS_PERCPT_LOCK_MAGIC);
205 }
206
207 void
208 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
209 {
210         LASSERT(pcl == (struct cfs_percpt_lock *) &CFS_PERCPT_LOCK_MAGIC);
211 }
212
213 # endif /* HAVE_LIBPTHREAD */
214 #endif /* __KERNEL__ */
215
216 /** free cpu-partition refcount */
217 void
218 cfs_percpt_atomic_free(cfs_atomic_t **refs)
219 {
220         cfs_percpt_free(refs);
221 }
222 CFS_EXPORT_SYMBOL(cfs_percpt_atomic_free);
223
224 /** allocate cpu-partition refcount with initial value @init_val */
225 cfs_atomic_t **
226 cfs_percpt_atomic_alloc(struct cfs_cpt_table *cptab, int init_val)
227 {
228         cfs_atomic_t    **refs;
229         cfs_atomic_t    *ref;
230         int             i;
231
232         refs = cfs_percpt_alloc(cptab, sizeof(*ref));
233         if (refs == NULL)
234                 return NULL;
235
236         cfs_percpt_for_each(ref, i, refs)
237                 cfs_atomic_set(ref, init_val);
238         return refs;
239 }
240 CFS_EXPORT_SYMBOL(cfs_percpt_atomic_alloc);
241
242 /** return sum of cpu-partition refs */
243 int
244 cfs_percpt_atomic_summary(cfs_atomic_t **refs)
245 {
246         cfs_atomic_t    *ref;
247         int             i;
248         int             val = 0;
249
250         cfs_percpt_for_each(ref, i, refs)
251                 val += cfs_atomic_read(ref);
252
253         return val;
254 }
255 CFS_EXPORT_SYMBOL(cfs_percpt_atomic_summary);