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