]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
staging: add Lustre file system client support
[karo-tx-linux.git] / drivers / staging / lustre / lustre / 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 #ifndef EXPORT_SYMTAB
34 # define EXPORT_SYMTAB
35 #endif
36 #define DEBUG_SUBSYSTEM S_LNET
37
38 #include <linux/libcfs/libcfs.h>
39
40
41 /** destroy cpu-partition lock, see libcfs_private.h for more detail */
42 void
43 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
44 {
45         LASSERT(pcl->pcl_locks != NULL);
46         LASSERT(!pcl->pcl_locked);
47
48         cfs_percpt_free(pcl->pcl_locks);
49         LIBCFS_FREE(pcl, sizeof(*pcl));
50 }
51 EXPORT_SYMBOL(cfs_percpt_lock_free);
52
53 /**
54  * create cpu-partition lock, see libcfs_private.h for more detail.
55  *
56  * cpu-partition lock is designed for large-scale SMP system, so we need to
57  * reduce cacheline conflict as possible as we can, that's the
58  * reason we always allocate cacheline-aligned memory block.
59  */
60 struct cfs_percpt_lock *
61 cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab)
62 {
63         struct cfs_percpt_lock  *pcl;
64         spinlock_t              *lock;
65         int                     i;
66
67         /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
68         LIBCFS_ALLOC(pcl, sizeof(*pcl));
69         if (pcl == NULL)
70                 return NULL;
71
72         pcl->pcl_cptab = cptab;
73         pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
74         if (pcl->pcl_locks == NULL) {
75                 LIBCFS_FREE(pcl, sizeof(*pcl));
76                 return NULL;
77         }
78
79         cfs_percpt_for_each(lock, i, pcl->pcl_locks)
80                 spin_lock_init(lock);
81
82         return pcl;
83 }
84 EXPORT_SYMBOL(cfs_percpt_lock_alloc);
85
86 /**
87  * lock a CPU partition
88  *
89  * \a index != CFS_PERCPT_LOCK_EX
90  *     hold private lock indexed by \a index
91  *
92  * \a index == CFS_PERCPT_LOCK_EX
93  *     exclusively lock @pcl and nobody can take private lock
94  */
95 void
96 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
97 {
98         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
99         int     i;
100
101         LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
102
103         if (ncpt == 1) {
104                 index = 0;
105         } else { /* serialize with exclusive lock */
106                 while (pcl->pcl_locked)
107                         cpu_relax();
108         }
109
110         if (likely(index != CFS_PERCPT_LOCK_EX)) {
111                 spin_lock(pcl->pcl_locks[index]);
112                 return;
113         }
114
115         /* exclusive lock request */
116         for (i = 0; i < ncpt; i++) {
117                 spin_lock(pcl->pcl_locks[i]);
118                 if (i == 0) {
119                         LASSERT(!pcl->pcl_locked);
120                         /* nobody should take private lock after this
121                          * so I wouldn't starve for too long time */
122                         pcl->pcl_locked = 1;
123                 }
124         }
125 }
126 EXPORT_SYMBOL(cfs_percpt_lock);
127
128 /** unlock a CPU partition */
129 void
130 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
131 {
132         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
133         int     i;
134
135         index = ncpt == 1 ? 0 : index;
136
137         if (likely(index != CFS_PERCPT_LOCK_EX)) {
138                 spin_unlock(pcl->pcl_locks[index]);
139                 return;
140         }
141
142         for (i = ncpt - 1; i >= 0; i--) {
143                 if (i == 0) {
144                         LASSERT(pcl->pcl_locked);
145                         pcl->pcl_locked = 0;
146                 }
147                 spin_unlock(pcl->pcl_locks[i]);
148         }
149 }
150 EXPORT_SYMBOL(cfs_percpt_unlock);
151
152
153 /** free cpu-partition refcount */
154 void
155 cfs_percpt_atomic_free(atomic_t **refs)
156 {
157         cfs_percpt_free(refs);
158 }
159 EXPORT_SYMBOL(cfs_percpt_atomic_free);
160
161 /** allocate cpu-partition refcount with initial value @init_val */
162 atomic_t **
163 cfs_percpt_atomic_alloc(struct cfs_cpt_table *cptab, int init_val)
164 {
165         atomic_t        **refs;
166         atomic_t        *ref;
167         int             i;
168
169         refs = cfs_percpt_alloc(cptab, sizeof(*ref));
170         if (refs == NULL)
171                 return NULL;
172
173         cfs_percpt_for_each(ref, i, refs)
174                 atomic_set(ref, init_val);
175         return refs;
176 }
177 EXPORT_SYMBOL(cfs_percpt_atomic_alloc);
178
179 /** return sum of cpu-partition refs */
180 int
181 cfs_percpt_atomic_summary(atomic_t **refs)
182 {
183         atomic_t        *ref;
184         int             i;
185         int             val = 0;
186
187         cfs_percpt_for_each(ref, i, refs)
188                 val += atomic_read(ref);
189
190         return val;
191 }
192 EXPORT_SYMBOL(cfs_percpt_atomic_summary);