Commit | Line | Data |
---|---|---|
d7e09d03 PT |
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, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2010, 2012, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | * | |
36 | * lustre/ldlm/ldlm_extent.c | |
37 | * | |
38 | * Author: Peter Braam <braam@clusterfs.com> | |
39 | * Author: Phil Schwan <phil@clusterfs.com> | |
40 | */ | |
41 | ||
42 | /** | |
43 | * This file contains implementation of EXTENT lock type | |
44 | * | |
45 | * EXTENT lock type is for locking a contiguous range of values, represented | |
46 | * by 64-bit starting and ending offsets (inclusive). There are several extent | |
47 | * lock modes, some of which may be mutually incompatible. Extent locks are | |
48 | * considered incompatible if their modes are incompatible and their extents | |
49 | * intersect. See the lock mode compatibility matrix in lustre_dlm.h. | |
50 | */ | |
51 | ||
52 | #define DEBUG_SUBSYSTEM S_LDLM | |
9fdaf8c0 | 53 | #include "../../include/linux/libcfs/libcfs.h" |
d7e09d03 PT |
54 | |
55 | #include <lustre_dlm.h> | |
56 | #include <obd_support.h> | |
57 | #include <obd.h> | |
58 | #include <obd_class.h> | |
59 | #include <lustre_lib.h> | |
60 | ||
61 | #include "ldlm_internal.h" | |
62 | ||
63 | ||
64 | /* When a lock is cancelled by a client, the KMS may undergo change if this | |
65 | * is the "highest lock". This function returns the new KMS value. | |
66 | * Caller must hold lr_lock already. | |
67 | * | |
68 | * NB: A lock on [x,y] protects a KMS of up to y + 1 bytes! */ | |
69 | __u64 ldlm_extent_shift_kms(struct ldlm_lock *lock, __u64 old_kms) | |
70 | { | |
71 | struct ldlm_resource *res = lock->l_resource; | |
72 | struct list_head *tmp; | |
73 | struct ldlm_lock *lck; | |
74 | __u64 kms = 0; | |
d7e09d03 PT |
75 | |
76 | /* don't let another thread in ldlm_extent_shift_kms race in | |
77 | * just after we finish and take our lock into account in its | |
78 | * calculation of the kms */ | |
79 | lock->l_flags |= LDLM_FL_KMS_IGNORE; | |
80 | ||
81 | list_for_each(tmp, &res->lr_granted) { | |
82 | lck = list_entry(tmp, struct ldlm_lock, l_res_link); | |
83 | ||
84 | if (lck->l_flags & LDLM_FL_KMS_IGNORE) | |
85 | continue; | |
86 | ||
87 | if (lck->l_policy_data.l_extent.end >= old_kms) | |
0a3bdb00 | 88 | return old_kms; |
d7e09d03 PT |
89 | |
90 | /* This extent _has_ to be smaller than old_kms (checked above) | |
91 | * so kms can only ever be smaller or the same as old_kms. */ | |
92 | if (lck->l_policy_data.l_extent.end + 1 > kms) | |
93 | kms = lck->l_policy_data.l_extent.end + 1; | |
94 | } | |
95 | LASSERTF(kms <= old_kms, "kms "LPU64" old_kms "LPU64"\n", kms, old_kms); | |
96 | ||
0a3bdb00 | 97 | return kms; |
d7e09d03 PT |
98 | } |
99 | EXPORT_SYMBOL(ldlm_extent_shift_kms); | |
100 | ||
101 | struct kmem_cache *ldlm_interval_slab; | |
102 | struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock) | |
103 | { | |
104 | struct ldlm_interval *node; | |
d7e09d03 PT |
105 | |
106 | LASSERT(lock->l_resource->lr_type == LDLM_EXTENT); | |
0be19afa | 107 | OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS); |
d7e09d03 | 108 | if (node == NULL) |
0a3bdb00 | 109 | return NULL; |
d7e09d03 PT |
110 | |
111 | INIT_LIST_HEAD(&node->li_group); | |
112 | ldlm_interval_attach(node, lock); | |
0a3bdb00 | 113 | return node; |
d7e09d03 PT |
114 | } |
115 | ||
116 | void ldlm_interval_free(struct ldlm_interval *node) | |
117 | { | |
118 | if (node) { | |
119 | LASSERT(list_empty(&node->li_group)); | |
120 | LASSERT(!interval_is_intree(&node->li_node)); | |
121 | OBD_SLAB_FREE(node, ldlm_interval_slab, sizeof(*node)); | |
122 | } | |
123 | } | |
124 | ||
125 | /* interval tree, for LDLM_EXTENT. */ | |
126 | void ldlm_interval_attach(struct ldlm_interval *n, | |
127 | struct ldlm_lock *l) | |
128 | { | |
129 | LASSERT(l->l_tree_node == NULL); | |
130 | LASSERT(l->l_resource->lr_type == LDLM_EXTENT); | |
131 | ||
132 | list_add_tail(&l->l_sl_policy, &n->li_group); | |
133 | l->l_tree_node = n; | |
134 | } | |
135 | ||
136 | struct ldlm_interval *ldlm_interval_detach(struct ldlm_lock *l) | |
137 | { | |
138 | struct ldlm_interval *n = l->l_tree_node; | |
139 | ||
140 | if (n == NULL) | |
141 | return NULL; | |
142 | ||
143 | LASSERT(!list_empty(&n->li_group)); | |
144 | l->l_tree_node = NULL; | |
145 | list_del_init(&l->l_sl_policy); | |
146 | ||
730ebc81 | 147 | return list_empty(&n->li_group) ? n : NULL; |
d7e09d03 PT |
148 | } |
149 | ||
150 | static inline int lock_mode_to_index(ldlm_mode_t mode) | |
151 | { | |
152 | int index; | |
153 | ||
154 | LASSERT(mode != 0); | |
155 | LASSERT(IS_PO2(mode)); | |
156 | for (index = -1; mode; index++, mode >>= 1) ; | |
157 | LASSERT(index < LCK_MODE_NUM); | |
158 | return index; | |
159 | } | |
160 | ||
161 | /** Add newly granted lock into interval tree for the resource. */ | |
162 | void ldlm_extent_add_lock(struct ldlm_resource *res, | |
163 | struct ldlm_lock *lock) | |
164 | { | |
165 | struct interval_node *found, **root; | |
166 | struct ldlm_interval *node; | |
167 | struct ldlm_extent *extent; | |
168 | int idx; | |
169 | ||
170 | LASSERT(lock->l_granted_mode == lock->l_req_mode); | |
171 | ||
172 | node = lock->l_tree_node; | |
173 | LASSERT(node != NULL); | |
174 | LASSERT(!interval_is_intree(&node->li_node)); | |
175 | ||
176 | idx = lock_mode_to_index(lock->l_granted_mode); | |
177 | LASSERT(lock->l_granted_mode == 1 << idx); | |
178 | LASSERT(lock->l_granted_mode == res->lr_itree[idx].lit_mode); | |
179 | ||
180 | /* node extent initialize */ | |
181 | extent = &lock->l_policy_data.l_extent; | |
182 | interval_set(&node->li_node, extent->start, extent->end); | |
183 | ||
184 | root = &res->lr_itree[idx].lit_root; | |
185 | found = interval_insert(&node->li_node, root); | |
186 | if (found) { /* The policy group found. */ | |
187 | struct ldlm_interval *tmp = ldlm_interval_detach(lock); | |
188 | LASSERT(tmp != NULL); | |
189 | ldlm_interval_free(tmp); | |
190 | ldlm_interval_attach(to_ldlm_interval(found), lock); | |
191 | } | |
192 | res->lr_itree[idx].lit_size++; | |
193 | ||
194 | /* even though we use interval tree to manage the extent lock, we also | |
195 | * add the locks into grant list, for debug purpose, .. */ | |
196 | ldlm_resource_add_lock(res, &res->lr_granted, lock); | |
197 | } | |
198 | ||
199 | /** Remove cancelled lock from resource interval tree. */ | |
200 | void ldlm_extent_unlink_lock(struct ldlm_lock *lock) | |
201 | { | |
202 | struct ldlm_resource *res = lock->l_resource; | |
203 | struct ldlm_interval *node = lock->l_tree_node; | |
204 | struct ldlm_interval_tree *tree; | |
205 | int idx; | |
206 | ||
207 | if (!node || !interval_is_intree(&node->li_node)) /* duplicate unlink */ | |
208 | return; | |
209 | ||
210 | idx = lock_mode_to_index(lock->l_granted_mode); | |
211 | LASSERT(lock->l_granted_mode == 1 << idx); | |
212 | tree = &res->lr_itree[idx]; | |
213 | ||
214 | LASSERT(tree->lit_root != NULL); /* assure the tree is not null */ | |
215 | ||
216 | tree->lit_size--; | |
217 | node = ldlm_interval_detach(lock); | |
218 | if (node) { | |
219 | interval_erase(&node->li_node, &tree->lit_root); | |
220 | ldlm_interval_free(node); | |
221 | } | |
222 | } | |
223 | ||
224 | void ldlm_extent_policy_wire_to_local(const ldlm_wire_policy_data_t *wpolicy, | |
225 | ldlm_policy_data_t *lpolicy) | |
226 | { | |
227 | memset(lpolicy, 0, sizeof(*lpolicy)); | |
228 | lpolicy->l_extent.start = wpolicy->l_extent.start; | |
229 | lpolicy->l_extent.end = wpolicy->l_extent.end; | |
230 | lpolicy->l_extent.gid = wpolicy->l_extent.gid; | |
231 | } | |
232 | ||
233 | void ldlm_extent_policy_local_to_wire(const ldlm_policy_data_t *lpolicy, | |
234 | ldlm_wire_policy_data_t *wpolicy) | |
235 | { | |
236 | memset(wpolicy, 0, sizeof(*wpolicy)); | |
237 | wpolicy->l_extent.start = lpolicy->l_extent.start; | |
238 | wpolicy->l_extent.end = lpolicy->l_extent.end; | |
239 | wpolicy->l_extent.gid = lpolicy->l_extent.gid; | |
240 | } |