Whamcloud - gitweb
721d56df917dbe05ca28a0dcb431132d6cd0680d
[fs/lustre-release.git] / lnet / lnet / 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  * GPL HEADER END
17  */
18 /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
19  * Copyright (c) 2012, 2015, Intel Corporation.
20  */
21 /* This file is part of Lustre, http://www.lustre.org/
22  *
23  * Author: liang@whamcloud.com
24  */
25
26 #define DEBUG_SUBSYSTEM S_LNET
27
28 #include <lnet/lib-lnet.h>
29
30 /** destroy cpu-partition lock, see libcfs_private.h for more detail */
31 void
32 cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
33 {
34         LASSERT(pcl->pcl_locks != NULL);
35         LASSERT(!pcl->pcl_locked);
36
37         cfs_percpt_free(pcl->pcl_locks);
38         LIBCFS_FREE(pcl, sizeof(*pcl));
39 }
40 EXPORT_SYMBOL(cfs_percpt_lock_free);
41
42 /**
43  * create cpu-partition lock, see libcfs_private.h for more detail.
44  *
45  * cpu-partition lock is designed for large-scale SMP system, so we need to
46  * reduce cacheline conflict as possible as we can, that's the
47  * reason we always allocate cacheline-aligned memory block.
48  */
49 struct cfs_percpt_lock *
50 cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
51                        struct lock_class_key *keys)
52 {
53         struct cfs_percpt_lock  *pcl;
54         spinlock_t              *lock;
55         int                     i;
56
57         /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
58         LIBCFS_ALLOC(pcl, sizeof(*pcl));
59         if (pcl == NULL)
60                 return NULL;
61
62         pcl->pcl_cptab = cptab;
63         pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
64         if (pcl->pcl_locks == NULL) {
65                 LIBCFS_FREE(pcl, sizeof(*pcl));
66                 return NULL;
67         }
68
69         if (keys == NULL) {
70                 CWARN("Cannot setup class key for percpt lock, you may see recursive locking warnings which are actually fake.\n");
71         }
72
73         cfs_percpt_for_each(lock, i, pcl->pcl_locks) {
74                 spin_lock_init(lock);
75                 if (keys != NULL)
76                         lockdep_set_class(lock, &keys[i]);
77         }
78
79         return pcl;
80 }
81 EXPORT_SYMBOL(cfs_percpt_lock_create);
82
83 /**
84  * lock a CPU partition
85  *
86  * \a index != CFS_PERCPT_LOCK_EX
87  *     hold private lock indexed by \a index
88  *
89  * \a index == CFS_PERCPT_LOCK_EX
90  *     exclusively lock @pcl and nobody can take private lock
91  */
92 void
93 cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
94 __acquires(pcl->pcl_locks)
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                          */
121                         pcl->pcl_locked = 1;
122                 }
123         }
124 }
125 EXPORT_SYMBOL(cfs_percpt_lock);
126
127 /** unlock a CPU partition */
128 void
129 cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
130 __releases(pcl->pcl_locks)
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);