Whamcloud - gitweb
LU-12501 utils: fix 'lfs df' printing loop
[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, 2015, 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 /** destroy cpu-partition lock, see libcfs_private.h for more detail */
38 void
39 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
40 {
41         LASSERT(pcl->pcl_locks != NULL);
42         LASSERT(!pcl->pcl_locked);
43
44         cfs_percpt_free(pcl->pcl_locks);
45         LIBCFS_FREE(pcl, sizeof(*pcl));
46 }
47 EXPORT_SYMBOL(cfs_percpt_lock_free);
48
49 /**
50  * create cpu-partition lock, see libcfs_private.h for more detail.
51  *
52  * cpu-partition lock is designed for large-scale SMP system, so we need to
53  * reduce cacheline conflict as possible as we can, that's the
54  * reason we always allocate cacheline-aligned memory block.
55  */
56 struct cfs_percpt_lock *
57 cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
58                        struct lock_class_key *keys)
59 {
60         struct cfs_percpt_lock  *pcl;
61         spinlock_t              *lock;
62         int                     i;
63
64         /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
65         LIBCFS_ALLOC(pcl, sizeof(*pcl));
66         if (pcl == NULL)
67                 return NULL;
68
69         pcl->pcl_cptab = cptab;
70         pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
71         if (pcl->pcl_locks == NULL) {
72                 LIBCFS_FREE(pcl, sizeof(*pcl));
73                 return NULL;
74         }
75
76         if (keys == NULL) {
77                 CWARN("Cannot setup class key for percpt lock, you may see "
78                       "recursive locking warnings which are actually fake.\n");
79         }
80
81         cfs_percpt_for_each(lock, i, pcl->pcl_locks) {
82                 spin_lock_init(lock);
83                 if (keys != NULL)
84                         lockdep_set_class(lock, &keys[i]);
85         }
86
87         return pcl;
88 }
89 EXPORT_SYMBOL(cfs_percpt_lock_create);
90
91 /**
92  * lock a CPU partition
93  *
94  * \a index != CFS_PERCPT_LOCK_EX
95  *     hold private lock indexed by \a index
96  *
97  * \a index == CFS_PERCPT_LOCK_EX
98  *     exclusively lock @pcl and nobody can take private lock
99  */
100 void
101 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
102 __acquires(pcl->pcl_locks)
103 {
104         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
105         int     i;
106
107         LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
108
109         if (ncpt == 1) {
110                 index = 0;
111         } else { /* serialize with exclusive lock */
112                 while (pcl->pcl_locked)
113                         cpu_relax();
114         }
115
116         if (likely(index != CFS_PERCPT_LOCK_EX)) {
117                 spin_lock(pcl->pcl_locks[index]);
118                 return;
119         }
120
121         /* exclusive lock request */
122         for (i = 0; i < ncpt; i++) {
123                 spin_lock(pcl->pcl_locks[i]);
124                 if (i == 0) {
125                         LASSERT(!pcl->pcl_locked);
126                         /* nobody should take private lock after this
127                          * so I wouldn't starve for too long time */
128                         pcl->pcl_locked = 1;
129                 }
130         }
131 }
132 EXPORT_SYMBOL(cfs_percpt_lock);
133
134 /** unlock a CPU partition */
135 void
136 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
137 __releases(pcl->pcl_locks)
138 {
139         int     ncpt = cfs_cpt_number(pcl->pcl_cptab);
140         int     i;
141
142         index = ncpt == 1 ? 0 : index;
143
144         if (likely(index != CFS_PERCPT_LOCK_EX)) {
145                 spin_unlock(pcl->pcl_locks[index]);
146                 return;
147         }
148
149         for (i = ncpt - 1; i >= 0; i--) {
150                 if (i == 0) {
151                         LASSERT(pcl->pcl_locked);
152                         pcl->pcl_locked = 0;
153                 }
154                 spin_unlock(pcl->pcl_locks[i]);
155         }
156 }
157 EXPORT_SYMBOL(cfs_percpt_unlock);