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 | |
6a5b99a4 | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 19 | * |
d7e09d03 PT |
20 | * GPL HEADER END |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
26 | * Copyright (c) 2011, 2012, Intel Corporation. | |
27 | */ | |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
30 | * Lustre is a trademark of Sun Microsystems, Inc. | |
31 | * | |
32 | * Client Extent Lock. | |
33 | * | |
34 | * Author: Nikita Danilov <nikita.danilov@sun.com> | |
d9d47901 | 35 | * Author: Jinshan Xiong <jinshan.xiong@intel.com> |
d7e09d03 PT |
36 | */ |
37 | ||
38 | #define DEBUG_SUBSYSTEM S_CLASS | |
39 | ||
610f7377 GKH |
40 | #include "../include/obd_class.h" |
41 | #include "../include/obd_support.h" | |
42 | #include "../include/lustre_fid.h" | |
d7e09d03 | 43 | #include <linux/list.h> |
610f7377 | 44 | #include "../include/cl_object.h" |
d7e09d03 PT |
45 | #include "cl_internal.h" |
46 | ||
06563b56 JX |
47 | static void cl_lock_trace0(int level, const struct lu_env *env, |
48 | const char *prefix, const struct cl_lock *lock, | |
49 | const char *func, const int line) | |
d7e09d03 | 50 | { |
06563b56 | 51 | struct cl_object_header *h = cl_object_header(lock->cll_descr.cld_obj); |
d7e09d03 | 52 | |
06563b56 JX |
53 | CDEBUG(level, "%s: %p (%p/%d) at %s():%d\n", |
54 | prefix, lock, env, h->coh_nesting, func, line); | |
d7e09d03 | 55 | } |
06563b56 JX |
56 | #define cl_lock_trace(level, env, prefix, lock) \ |
57 | cl_lock_trace0(level, env, prefix, lock, __func__, __LINE__) | |
d7e09d03 | 58 | |
d7e09d03 | 59 | /** |
06563b56 | 60 | * Adds lock slice to the compound lock. |
d7e09d03 | 61 | * |
06563b56 JX |
62 | * This is called by cl_object_operations::coo_lock_init() methods to add a |
63 | * per-layer state to the lock. New state is added at the end of | |
64 | * cl_lock::cll_layers list, that is, it is at the bottom of the stack. | |
d7e09d03 | 65 | * |
06563b56 | 66 | * \see cl_req_slice_add(), cl_page_slice_add(), cl_io_slice_add() |
d7e09d03 | 67 | */ |
06563b56 JX |
68 | void cl_lock_slice_add(struct cl_lock *lock, struct cl_lock_slice *slice, |
69 | struct cl_object *obj, | |
70 | const struct cl_lock_operations *ops) | |
d7e09d03 | 71 | { |
06563b56 JX |
72 | slice->cls_lock = lock; |
73 | list_add_tail(&slice->cls_linkage, &lock->cll_layers); | |
74 | slice->cls_obj = obj; | |
75 | slice->cls_ops = ops; | |
d7e09d03 | 76 | } |
06563b56 | 77 | EXPORT_SYMBOL(cl_lock_slice_add); |
d7e09d03 | 78 | |
06563b56 | 79 | void cl_lock_fini(const struct lu_env *env, struct cl_lock *lock) |
d7e09d03 | 80 | { |
06563b56 | 81 | cl_lock_trace(D_DLMTRACE, env, "destroy lock", lock); |
d7e09d03 | 82 | |
06563b56 JX |
83 | while (!list_empty(&lock->cll_layers)) { |
84 | struct cl_lock_slice *slice; | |
d7e09d03 | 85 | |
06563b56 JX |
86 | slice = list_entry(lock->cll_layers.next, |
87 | struct cl_lock_slice, cls_linkage); | |
88 | list_del_init(lock->cll_layers.next); | |
89 | slice->cls_ops->clo_fini(env, slice); | |
90 | } | |
91 | POISON(lock, 0x5a, sizeof(*lock)); | |
d7e09d03 | 92 | } |
06563b56 | 93 | EXPORT_SYMBOL(cl_lock_fini); |
d7e09d03 | 94 | |
06563b56 JX |
95 | int cl_lock_init(const struct lu_env *env, struct cl_lock *lock, |
96 | const struct cl_io *io) | |
d7e09d03 | 97 | { |
06563b56 JX |
98 | struct cl_object *obj = lock->cll_descr.cld_obj; |
99 | struct cl_object *scan; | |
100 | int result = 0; | |
d7e09d03 | 101 | |
06563b56 JX |
102 | /* Make sure cl_lock::cll_descr is initialized. */ |
103 | LASSERT(obj); | |
d7e09d03 | 104 | |
06563b56 JX |
105 | INIT_LIST_HEAD(&lock->cll_layers); |
106 | list_for_each_entry(scan, &obj->co_lu.lo_header->loh_layers, | |
107 | co_lu.lo_linkage) { | |
108 | result = scan->co_ops->coo_lock_init(env, scan, lock, io); | |
109 | if (result != 0) { | |
110 | cl_lock_fini(env, lock); | |
d7e09d03 PT |
111 | break; |
112 | } | |
06563b56 | 113 | } |
d7e09d03 | 114 | |
0a3bdb00 | 115 | return result; |
d7e09d03 | 116 | } |
06563b56 | 117 | EXPORT_SYMBOL(cl_lock_init); |
d7e09d03 PT |
118 | |
119 | /** | |
06563b56 JX |
120 | * Returns a slice with a lock, corresponding to the given layer in the |
121 | * device stack. | |
d7e09d03 | 122 | * |
06563b56 | 123 | * \see cl_page_at() |
d7e09d03 | 124 | */ |
06563b56 JX |
125 | const struct cl_lock_slice *cl_lock_at(const struct cl_lock *lock, |
126 | const struct lu_device_type *dtype) | |
d7e09d03 PT |
127 | { |
128 | const struct cl_lock_slice *slice; | |
d7e09d03 | 129 | |
06563b56 JX |
130 | list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { |
131 | if (slice->cls_obj->co_lu.lo_dev->ld_type == dtype) | |
132 | return slice; | |
d7e09d03 | 133 | } |
06563b56 | 134 | return NULL; |
d7e09d03 | 135 | } |
06563b56 | 136 | EXPORT_SYMBOL(cl_lock_at); |
d7e09d03 | 137 | |
06563b56 | 138 | void cl_lock_cancel(const struct lu_env *env, struct cl_lock *lock) |
d7e09d03 PT |
139 | { |
140 | const struct cl_lock_slice *slice; | |
d7e09d03 | 141 | |
06563b56 | 142 | cl_lock_trace(D_DLMTRACE, env, "cancel lock", lock); |
d7e09d03 | 143 | list_for_each_entry_reverse(slice, &lock->cll_layers, cls_linkage) { |
06563b56 JX |
144 | if (slice->cls_ops->clo_cancel) |
145 | slice->cls_ops->clo_cancel(env, slice); | |
d7e09d03 | 146 | } |
d7e09d03 | 147 | } |
d7e09d03 PT |
148 | EXPORT_SYMBOL(cl_lock_cancel); |
149 | ||
150 | /** | |
06563b56 JX |
151 | * Enqueue a lock. |
152 | * \param anchor: if we need to wait for resources before getting the lock, | |
153 | * use @anchor for the purpose. | |
154 | * \retval 0 enqueue successfully | |
155 | * \retval <0 error code | |
d7e09d03 | 156 | */ |
06563b56 JX |
157 | int cl_lock_enqueue(const struct lu_env *env, struct cl_io *io, |
158 | struct cl_lock *lock, struct cl_sync_io *anchor) | |
d7e09d03 | 159 | { |
06563b56 JX |
160 | const struct cl_lock_slice *slice; |
161 | int rc = -ENOSYS; | |
d7e09d03 | 162 | |
06563b56 JX |
163 | list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { |
164 | if (!slice->cls_ops->clo_enqueue) | |
165 | continue; | |
d7e09d03 | 166 | |
06563b56 JX |
167 | rc = slice->cls_ops->clo_enqueue(env, slice, io, anchor); |
168 | if (rc != 0) | |
d7e09d03 PT |
169 | break; |
170 | } | |
06563b56 | 171 | return rc; |
d7e09d03 | 172 | } |
06563b56 | 173 | EXPORT_SYMBOL(cl_lock_enqueue); |
d7e09d03 | 174 | |
d7e09d03 | 175 | /** |
06563b56 JX |
176 | * Main high-level entry point of cl_lock interface that finds existing or |
177 | * enqueues new lock matching given description. | |
d7e09d03 | 178 | */ |
06563b56 JX |
179 | int cl_lock_request(const struct lu_env *env, struct cl_io *io, |
180 | struct cl_lock *lock) | |
d7e09d03 | 181 | { |
06563b56 JX |
182 | struct cl_sync_io *anchor = NULL; |
183 | __u32 enq_flags = lock->cll_descr.cld_enq_flags; | |
184 | int rc; | |
d7e09d03 | 185 | |
06563b56 JX |
186 | rc = cl_lock_init(env, lock, io); |
187 | if (rc < 0) | |
188 | return rc; | |
d7e09d03 | 189 | |
06563b56 JX |
190 | if ((enq_flags & CEF_ASYNC) && !(enq_flags & CEF_AGL)) { |
191 | anchor = &cl_env_info(env)->clt_anchor; | |
192 | cl_sync_io_init(anchor, 1, cl_sync_io_end); | |
d7e09d03 | 193 | } |
d7e09d03 | 194 | |
06563b56 | 195 | rc = cl_lock_enqueue(env, io, lock, anchor); |
d7e09d03 | 196 | |
06563b56 JX |
197 | if (anchor) { |
198 | int rc2; | |
d7e09d03 | 199 | |
06563b56 JX |
200 | /* drop the reference count held at initialization time */ |
201 | cl_sync_io_note(env, anchor, 0); | |
202 | rc2 = cl_sync_io_wait(env, anchor, 0); | |
203 | if (rc2 < 0 && rc == 0) | |
204 | rc = rc2; | |
205 | } | |
d7e09d03 | 206 | |
06563b56 JX |
207 | if (rc < 0) |
208 | cl_lock_release(env, lock); | |
d7e09d03 | 209 | |
06563b56 | 210 | return rc; |
d7e09d03 PT |
211 | } |
212 | EXPORT_SYMBOL(cl_lock_request); | |
213 | ||
d7e09d03 PT |
214 | /** |
215 | * Releases a hold and a reference on a lock, obtained by cl_lock_hold(). | |
216 | */ | |
06563b56 | 217 | void cl_lock_release(const struct lu_env *env, struct cl_lock *lock) |
d7e09d03 | 218 | { |
d7e09d03 | 219 | cl_lock_trace(D_DLMTRACE, env, "release lock", lock); |
06563b56 JX |
220 | cl_lock_cancel(env, lock); |
221 | cl_lock_fini(env, lock); | |
d7e09d03 PT |
222 | } |
223 | EXPORT_SYMBOL(cl_lock_release); | |
224 | ||
d7e09d03 PT |
225 | const char *cl_lock_mode_name(const enum cl_lock_mode mode) |
226 | { | |
227 | static const char *names[] = { | |
d7e09d03 PT |
228 | [CLM_READ] = "R", |
229 | [CLM_WRITE] = "W", | |
230 | [CLM_GROUP] = "G" | |
231 | }; | |
232 | if (0 <= mode && mode < ARRAY_SIZE(names)) | |
233 | return names[mode]; | |
234 | else | |
235 | return "U"; | |
236 | } | |
237 | EXPORT_SYMBOL(cl_lock_mode_name); | |
238 | ||
239 | /** | |
240 | * Prints human readable representation of a lock description. | |
241 | */ | |
242 | void cl_lock_descr_print(const struct lu_env *env, void *cookie, | |
926d6fb2 OD |
243 | lu_printer_t printer, |
244 | const struct cl_lock_descr *descr) | |
d7e09d03 PT |
245 | { |
246 | const struct lu_fid *fid; | |
247 | ||
248 | fid = lu_object_fid(&descr->cld_obj->co_lu); | |
249 | (*printer)(env, cookie, DDESCR"@"DFID, PDESCR(descr), PFID(fid)); | |
250 | } | |
251 | EXPORT_SYMBOL(cl_lock_descr_print); | |
252 | ||
253 | /** | |
254 | * Prints human readable representation of \a lock to the \a f. | |
255 | */ | |
256 | void cl_lock_print(const struct lu_env *env, void *cookie, | |
257 | lu_printer_t printer, const struct cl_lock *lock) | |
258 | { | |
259 | const struct cl_lock_slice *slice; | |
06563b56 JX |
260 | |
261 | (*printer)(env, cookie, "lock@%p", lock); | |
d7e09d03 PT |
262 | cl_lock_descr_print(env, cookie, printer, &lock->cll_descr); |
263 | (*printer)(env, cookie, " {\n"); | |
264 | ||
265 | list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { | |
266 | (*printer)(env, cookie, " %s@%p: ", | |
267 | slice->cls_obj->co_lu.lo_dev->ld_type->ldt_name, | |
268 | slice); | |
cce3c2da | 269 | if (slice->cls_ops->clo_print) |
d7e09d03 PT |
270 | slice->cls_ops->clo_print(env, cookie, printer, slice); |
271 | (*printer)(env, cookie, "\n"); | |
272 | } | |
273 | (*printer)(env, cookie, "} lock@%p\n", lock); | |
274 | } | |
275 | EXPORT_SYMBOL(cl_lock_print); |