Merge branch 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / staging / lustre / lustre / obdclass / cl_lock.c
CommitLineData
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
47static 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
68void 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 77EXPORT_SYMBOL(cl_lock_slice_add);
d7e09d03 78
06563b56 79void 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 93EXPORT_SYMBOL(cl_lock_fini);
d7e09d03 94
06563b56
JX
95int 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 117EXPORT_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
125const 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 136EXPORT_SYMBOL(cl_lock_at);
d7e09d03 137
06563b56 138void 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
148EXPORT_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
157int 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 173EXPORT_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
179int 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}
212EXPORT_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 217void 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}
223EXPORT_SYMBOL(cl_lock_release);
224
d7e09d03
PT
225const 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}
237EXPORT_SYMBOL(cl_lock_mode_name);
238
239/**
240 * Prints human readable representation of a lock description.
241 */
242void 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}
251EXPORT_SYMBOL(cl_lock_descr_print);
252
253/**
254 * Prints human readable representation of \a lock to the \a f.
255 */
256void 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}
275EXPORT_SYMBOL(cl_lock_print);