add hlist_bl_lock/unlock helpers
[linux-2.6.git] / fs / gfs2 / lock_dlm.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License version 2.
8  */
9
10 #include <linux/fs.h>
11 #include <linux/dlm.h>
12 #include <linux/slab.h>
13 #include <linux/types.h>
14 #include <linux/gfs2_ondisk.h>
15
16 #include "incore.h"
17 #include "glock.h"
18 #include "util.h"
19
20
21 static void gdlm_ast(void *arg)
22 {
23         struct gfs2_glock *gl = arg;
24         unsigned ret = gl->gl_state;
25
26         BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
27
28         if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
29                 memset(gl->gl_lvb, 0, GDLM_LVB_SIZE);
30
31         switch (gl->gl_lksb.sb_status) {
32         case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */
33                 gfs2_glock_free(gl);
34                 return;
35         case -DLM_ECANCEL: /* Cancel while getting lock */
36                 ret |= LM_OUT_CANCELED;
37                 goto out;
38         case -EAGAIN: /* Try lock fails */
39         case -EDEADLK: /* Deadlock detected */
40                 goto out;
41         case -ETIMEDOUT: /* Canceled due to timeout */
42                 ret |= LM_OUT_ERROR;
43                 goto out;
44         case 0: /* Success */
45                 break;
46         default: /* Something unexpected */
47                 BUG();
48         }
49
50         ret = gl->gl_req;
51         if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) {
52                 if (gl->gl_req == LM_ST_SHARED)
53                         ret = LM_ST_DEFERRED;
54                 else if (gl->gl_req == LM_ST_DEFERRED)
55                         ret = LM_ST_SHARED;
56                 else
57                         BUG();
58         }
59
60         set_bit(GLF_INITIAL, &gl->gl_flags);
61         gfs2_glock_complete(gl, ret);
62         return;
63 out:
64         if (!test_bit(GLF_INITIAL, &gl->gl_flags))
65                 gl->gl_lksb.sb_lkid = 0;
66         gfs2_glock_complete(gl, ret);
67 }
68
69 static void gdlm_bast(void *arg, int mode)
70 {
71         struct gfs2_glock *gl = arg;
72
73         switch (mode) {
74         case DLM_LOCK_EX:
75                 gfs2_glock_cb(gl, LM_ST_UNLOCKED);
76                 break;
77         case DLM_LOCK_CW:
78                 gfs2_glock_cb(gl, LM_ST_DEFERRED);
79                 break;
80         case DLM_LOCK_PR:
81                 gfs2_glock_cb(gl, LM_ST_SHARED);
82                 break;
83         default:
84                 printk(KERN_ERR "unknown bast mode %d", mode);
85                 BUG();
86         }
87 }
88
89 /* convert gfs lock-state to dlm lock-mode */
90
91 static int make_mode(const unsigned int lmstate)
92 {
93         switch (lmstate) {
94         case LM_ST_UNLOCKED:
95                 return DLM_LOCK_NL;
96         case LM_ST_EXCLUSIVE:
97                 return DLM_LOCK_EX;
98         case LM_ST_DEFERRED:
99                 return DLM_LOCK_CW;
100         case LM_ST_SHARED:
101                 return DLM_LOCK_PR;
102         }
103         printk(KERN_ERR "unknown LM state %d", lmstate);
104         BUG();
105         return -1;
106 }
107
108 static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
109                       const int req)
110 {
111         u32 lkf = 0;
112
113         if (gfs_flags & LM_FLAG_TRY)
114                 lkf |= DLM_LKF_NOQUEUE;
115
116         if (gfs_flags & LM_FLAG_TRY_1CB) {
117                 lkf |= DLM_LKF_NOQUEUE;
118                 lkf |= DLM_LKF_NOQUEUEBAST;
119         }
120
121         if (gfs_flags & LM_FLAG_PRIORITY) {
122                 lkf |= DLM_LKF_NOORDER;
123                 lkf |= DLM_LKF_HEADQUE;
124         }
125
126         if (gfs_flags & LM_FLAG_ANY) {
127                 if (req == DLM_LOCK_PR)
128                         lkf |= DLM_LKF_ALTCW;
129                 else if (req == DLM_LOCK_CW)
130                         lkf |= DLM_LKF_ALTPR;
131                 else
132                         BUG();
133         }
134
135         if (lkid != 0) 
136                 lkf |= DLM_LKF_CONVERT;
137
138         lkf |= DLM_LKF_VALBLK;
139
140         return lkf;
141 }
142
143 static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
144                      unsigned int flags)
145 {
146         struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
147         int req;
148         u32 lkf;
149
150         req = make_mode(req_state);
151         lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
152
153         /*
154          * Submit the actual lock request.
155          */
156
157         return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
158                         GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
159 }
160
161 static void gdlm_put_lock(struct gfs2_glock *gl)
162 {
163         struct gfs2_sbd *sdp = gl->gl_sbd;
164         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
165         int error;
166
167         if (gl->gl_lksb.sb_lkid == 0) {
168                 gfs2_glock_free(gl);
169                 return;
170         }
171
172         error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
173                            NULL, gl);
174         if (error) {
175                 printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n",
176                        gl->gl_name.ln_type,
177                        (unsigned long long)gl->gl_name.ln_number, error);
178                 return;
179         }
180 }
181
182 static void gdlm_cancel(struct gfs2_glock *gl)
183 {
184         struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
185         dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
186 }
187
188 static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
189 {
190         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
191         int error;
192
193         if (fsname == NULL) {
194                 fs_info(sdp, "no fsname found\n");
195                 return -EINVAL;
196         }
197
198         error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm,
199                                   DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
200                                   (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
201                                   GDLM_LVB_SIZE);
202         if (error)
203                 printk(KERN_ERR "dlm_new_lockspace error %d", error);
204
205         return error;
206 }
207
208 static void gdlm_unmount(struct gfs2_sbd *sdp)
209 {
210         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
211
212         if (ls->ls_dlm) {
213                 dlm_release_lockspace(ls->ls_dlm, 2);
214                 ls->ls_dlm = NULL;
215         }
216 }
217
218 static const match_table_t dlm_tokens = {
219         { Opt_jid, "jid=%d"},
220         { Opt_id, "id=%d"},
221         { Opt_first, "first=%d"},
222         { Opt_nodir, "nodir=%d"},
223         { Opt_err, NULL },
224 };
225
226 const struct lm_lockops gfs2_dlm_ops = {
227         .lm_proto_name = "lock_dlm",
228         .lm_mount = gdlm_mount,
229         .lm_unmount = gdlm_unmount,
230         .lm_put_lock = gdlm_put_lock,
231         .lm_lock = gdlm_lock,
232         .lm_cancel = gdlm_cancel,
233         .lm_tokens = &dlm_tokens,
234 };
235