]>
Commit | Line | Data |
---|---|---|
24ef1815 JB |
1 | /* -*- mode: c; c-basic-offset: 8; -*- |
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | |
3 | * | |
4 | * stackglue.c | |
5 | * | |
6 | * Code which implements an OCFS2 specific interface to underlying | |
7 | * cluster stacks. | |
8 | * | |
9 | * Copyright (C) 2007 Oracle. All rights reserved. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public | |
13 | * License as published by the Free Software Foundation, version 2. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * General Public License for more details. | |
19 | */ | |
20 | ||
7431cd7e | 21 | #include "cluster/masklog.h" |
24ef1815 JB |
22 | #include "stackglue.h" |
23 | ||
24 | static struct ocfs2_locking_protocol *lproto; | |
25 | ||
bd3e7610 JB |
26 | /* These should be identical */ |
27 | #if (DLM_LOCK_IV != LKM_IVMODE) | |
28 | # error Lock modes do not match | |
29 | #endif | |
30 | #if (DLM_LOCK_NL != LKM_NLMODE) | |
31 | # error Lock modes do not match | |
32 | #endif | |
33 | #if (DLM_LOCK_CR != LKM_CRMODE) | |
34 | # error Lock modes do not match | |
35 | #endif | |
36 | #if (DLM_LOCK_CW != LKM_CWMODE) | |
37 | # error Lock modes do not match | |
38 | #endif | |
39 | #if (DLM_LOCK_PR != LKM_PRMODE) | |
40 | # error Lock modes do not match | |
41 | #endif | |
42 | #if (DLM_LOCK_PW != LKM_PWMODE) | |
43 | # error Lock modes do not match | |
44 | #endif | |
45 | #if (DLM_LOCK_EX != LKM_EXMODE) | |
46 | # error Lock modes do not match | |
47 | #endif | |
48 | static inline int mode_to_o2dlm(int mode) | |
49 | { | |
50 | BUG_ON(mode > LKM_MAXMODE); | |
51 | ||
52 | return mode; | |
53 | } | |
54 | ||
55 | #define map_flag(_generic, _o2dlm) \ | |
56 | if (flags & (_generic)) { \ | |
57 | flags &= ~(_generic); \ | |
58 | o2dlm_flags |= (_o2dlm); \ | |
59 | } | |
60 | static int flags_to_o2dlm(u32 flags) | |
61 | { | |
62 | int o2dlm_flags = 0; | |
63 | ||
64 | map_flag(DLM_LKF_NOQUEUE, LKM_NOQUEUE); | |
65 | map_flag(DLM_LKF_CANCEL, LKM_CANCEL); | |
66 | map_flag(DLM_LKF_CONVERT, LKM_CONVERT); | |
67 | map_flag(DLM_LKF_VALBLK, LKM_VALBLK); | |
68 | map_flag(DLM_LKF_IVVALBLK, LKM_INVVALBLK); | |
69 | map_flag(DLM_LKF_ORPHAN, LKM_ORPHAN); | |
70 | map_flag(DLM_LKF_FORCEUNLOCK, LKM_FORCE); | |
71 | map_flag(DLM_LKF_TIMEOUT, LKM_TIMEOUT); | |
72 | map_flag(DLM_LKF_LOCAL, LKM_LOCAL); | |
73 | ||
74 | /* map_flag() should have cleared every flag passed in */ | |
75 | BUG_ON(flags != 0); | |
76 | ||
77 | return o2dlm_flags; | |
78 | } | |
79 | #undef map_flag | |
80 | ||
7431cd7e JB |
81 | /* |
82 | * Map an o2dlm status to standard errno values. | |
83 | * | |
84 | * o2dlm only uses a handful of these, and returns even fewer to the | |
85 | * caller. Still, we try to assign sane values to each error. | |
86 | * | |
87 | * The following value pairs have special meanings to dlmglue, thus | |
88 | * the right hand side needs to stay unique - never duplicate the | |
89 | * mapping elsewhere in the table! | |
90 | * | |
91 | * DLM_NORMAL: 0 | |
92 | * DLM_NOTQUEUED: -EAGAIN | |
93 | * DLM_CANCELGRANT: -DLM_ECANCEL | |
94 | * DLM_CANCEL: -DLM_EUNLOCK | |
95 | */ | |
96 | /* Keep in sync with dlmapi.h */ | |
97 | static int status_map[] = { | |
98 | [DLM_NORMAL] = 0, /* Success */ | |
99 | [DLM_GRANTED] = -EINVAL, | |
100 | [DLM_DENIED] = -EACCES, | |
101 | [DLM_DENIED_NOLOCKS] = -EACCES, | |
102 | [DLM_WORKING] = -EBUSY, | |
103 | [DLM_BLOCKED] = -EINVAL, | |
104 | [DLM_BLOCKED_ORPHAN] = -EINVAL, | |
105 | [DLM_DENIED_GRACE_PERIOD] = -EACCES, | |
106 | [DLM_SYSERR] = -ENOMEM, /* It is what it is */ | |
107 | [DLM_NOSUPPORT] = -EPROTO, | |
108 | [DLM_CANCELGRANT] = -DLM_ECANCEL, /* Cancel after grant */ | |
109 | [DLM_IVLOCKID] = -EINVAL, | |
110 | [DLM_SYNC] = -EINVAL, | |
111 | [DLM_BADTYPE] = -EINVAL, | |
112 | [DLM_BADRESOURCE] = -EINVAL, | |
113 | [DLM_MAXHANDLES] = -ENOMEM, | |
114 | [DLM_NOCLINFO] = -EINVAL, | |
115 | [DLM_NOLOCKMGR] = -EINVAL, | |
116 | [DLM_NOPURGED] = -EINVAL, | |
117 | [DLM_BADARGS] = -EINVAL, | |
118 | [DLM_VOID] = -EINVAL, | |
119 | [DLM_NOTQUEUED] = -EAGAIN, /* Trylock failed */ | |
120 | [DLM_IVBUFLEN] = -EINVAL, | |
121 | [DLM_CVTUNGRANT] = -EPERM, | |
122 | [DLM_BADPARAM] = -EINVAL, | |
123 | [DLM_VALNOTVALID] = -EINVAL, | |
124 | [DLM_REJECTED] = -EPERM, | |
125 | [DLM_ABORT] = -EINVAL, | |
126 | [DLM_CANCEL] = -DLM_EUNLOCK, /* Successful cancel */ | |
127 | [DLM_IVRESHANDLE] = -EINVAL, | |
128 | [DLM_DEADLOCK] = -EDEADLK, | |
129 | [DLM_DENIED_NOASTS] = -EINVAL, | |
130 | [DLM_FORWARD] = -EINVAL, | |
131 | [DLM_TIMEOUT] = -ETIMEDOUT, | |
132 | [DLM_IVGROUPID] = -EINVAL, | |
133 | [DLM_VERS_CONFLICT] = -EOPNOTSUPP, | |
134 | [DLM_BAD_DEVICE_PATH] = -ENOENT, | |
135 | [DLM_NO_DEVICE_PERMISSION] = -EPERM, | |
136 | [DLM_NO_CONTROL_DEVICE] = -ENOENT, | |
137 | [DLM_RECOVERING] = -ENOTCONN, | |
138 | [DLM_MIGRATING] = -ERESTART, | |
139 | [DLM_MAXSTATS] = -EINVAL, | |
140 | }; | |
141 | static int dlm_status_to_errno(enum dlm_status status) | |
142 | { | |
143 | BUG_ON(status > (sizeof(status_map) / sizeof(status_map[0]))); | |
144 | ||
145 | return status_map[status]; | |
146 | } | |
147 | ||
148 | static void o2dlm_lock_ast_wrapper(void *astarg) | |
149 | { | |
150 | BUG_ON(lproto == NULL); | |
151 | ||
152 | lproto->lp_lock_ast(astarg); | |
153 | } | |
154 | ||
155 | static void o2dlm_blocking_ast_wrapper(void *astarg, int level) | |
156 | { | |
157 | BUG_ON(lproto == NULL); | |
158 | ||
159 | lproto->lp_blocking_ast(astarg, level); | |
160 | } | |
161 | ||
162 | static void o2dlm_unlock_ast_wrapper(void *astarg, enum dlm_status status) | |
163 | { | |
164 | int error; | |
165 | ||
166 | BUG_ON(lproto == NULL); | |
167 | ||
168 | /* | |
169 | * XXX: CANCEL values are sketchy. | |
170 | * | |
171 | * Currently we have preserved the o2dlm paradigm. You can get | |
172 | * unlock_ast() whether the cancel succeded or not. | |
173 | * | |
174 | * First, we're going to pass DLM_EUNLOCK just like fs/dlm does for | |
175 | * successful unlocks. That is a clean behavior. | |
176 | * | |
177 | * In o2dlm, you can get both the lock_ast() for the lock being | |
178 | * granted and the unlock_ast() for the CANCEL failing. A | |
179 | * successful cancel sends DLM_NORMAL here. If the | |
180 | * lock grant happened before the cancel arrived, you get | |
181 | * DLM_CANCELGRANT. For now, we'll use DLM_ECANCEL to signify | |
182 | * CANCELGRANT - the CANCEL was supposed to happen but didn't. We | |
183 | * can then use DLM_EUNLOCK to signify a successful CANCEL - | |
184 | * effectively, the CANCEL caused the lock to roll back. | |
185 | * | |
186 | * In the future, we will likely move the o2dlm to send only one | |
187 | * ast - either unlock_ast() for a successful CANCEL or lock_ast() | |
188 | * when the grant succeeds. At that point, we'll send DLM_ECANCEL | |
189 | * for all cancel results (CANCELGRANT will no longer exist). | |
190 | */ | |
191 | error = dlm_status_to_errno(status); | |
192 | ||
193 | /* Successful unlock is DLM_EUNLOCK */ | |
194 | if (!error) | |
195 | error = -DLM_EUNLOCK; | |
196 | ||
197 | lproto->lp_unlock_ast(astarg, error); | |
198 | } | |
199 | ||
200 | int ocfs2_dlm_lock(struct dlm_ctxt *dlm, | |
24ef1815 JB |
201 | int mode, |
202 | struct dlm_lockstatus *lksb, | |
203 | u32 flags, | |
204 | void *name, | |
205 | unsigned int namelen, | |
206 | void *astarg) | |
207 | { | |
7431cd7e | 208 | enum dlm_status status; |
bd3e7610 JB |
209 | int o2dlm_mode = mode_to_o2dlm(mode); |
210 | int o2dlm_flags = flags_to_o2dlm(flags); | |
7431cd7e | 211 | int ret; |
bd3e7610 | 212 | |
24ef1815 | 213 | BUG_ON(lproto == NULL); |
bd3e7610 | 214 | |
7431cd7e JB |
215 | status = dlmlock(dlm, o2dlm_mode, lksb, o2dlm_flags, name, namelen, |
216 | o2dlm_lock_ast_wrapper, astarg, | |
217 | o2dlm_blocking_ast_wrapper); | |
218 | ret = dlm_status_to_errno(status); | |
219 | return ret; | |
24ef1815 JB |
220 | } |
221 | ||
7431cd7e | 222 | int ocfs2_dlm_unlock(struct dlm_ctxt *dlm, |
24ef1815 JB |
223 | struct dlm_lockstatus *lksb, |
224 | u32 flags, | |
225 | void *astarg) | |
226 | { | |
7431cd7e | 227 | enum dlm_status status; |
bd3e7610 | 228 | int o2dlm_flags = flags_to_o2dlm(flags); |
7431cd7e | 229 | int ret; |
bd3e7610 | 230 | |
24ef1815 JB |
231 | BUG_ON(lproto == NULL); |
232 | ||
7431cd7e JB |
233 | status = dlmunlock(dlm, lksb, o2dlm_flags, |
234 | o2dlm_unlock_ast_wrapper, astarg); | |
235 | ret = dlm_status_to_errno(status); | |
236 | return ret; | |
24ef1815 JB |
237 | } |
238 | ||
239 | ||
240 | void o2cb_get_stack(struct ocfs2_locking_protocol *proto) | |
241 | { | |
242 | BUG_ON(proto == NULL); | |
243 | ||
244 | lproto = proto; | |
245 | } | |
246 | ||
247 | void o2cb_put_stack(void) | |
248 | { | |
249 | lproto = NULL; | |
250 | } |