]> bbs.cooldavid.org Git - net-next-2.6.git/blob - fs/gfs2/lock_dlm.c
569b46240f613c1a17e4ff0653c1bb53dc59cfe1
[net-next-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/types.h>
13 #include <linux/gfs2_ondisk.h>
14
15 #include "incore.h"
16 #include "glock.h"
17 #include "util.h"
18
19
20 static void gdlm_ast(void *arg)
21 {
22         struct gfs2_glock *gl = arg;
23         unsigned ret = gl->gl_state;
24         struct gfs2_sbd *sdp = gl->gl_sbd;
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                 if (gl->gl_ops->go_flags & GLOF_ASPACE)
34                         kmem_cache_free(gfs2_glock_aspace_cachep, gl);
35                 else
36                         kmem_cache_free(gfs2_glock_cachep, gl);
37                 if (atomic_dec_and_test(&sdp->sd_glock_disposal))
38                         wake_up(&sdp->sd_glock_wait);
39                 return;
40         case -DLM_ECANCEL: /* Cancel while getting lock */
41                 ret |= LM_OUT_CANCELED;
42                 goto out;
43         case -EAGAIN: /* Try lock fails */
44                 goto out;
45         case -EINVAL: /* Invalid */
46         case -ENOMEM: /* Out of memory */
47                 ret |= LM_OUT_ERROR;
48                 goto out;
49         case 0: /* Success */
50                 break;
51         default: /* Something unexpected */
52                 BUG();
53         }
54
55         ret = gl->gl_req;
56         if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) {
57                 if (gl->gl_req == LM_ST_SHARED)
58                         ret = LM_ST_DEFERRED;
59                 else if (gl->gl_req == LM_ST_DEFERRED)
60                         ret = LM_ST_SHARED;
61                 else
62                         BUG();
63         }
64
65         set_bit(GLF_INITIAL, &gl->gl_flags);
66         gfs2_glock_complete(gl, ret);
67         return;
68 out:
69         if (!test_bit(GLF_INITIAL, &gl->gl_flags))
70                 gl->gl_lksb.sb_lkid = 0;
71         gfs2_glock_complete(gl, ret);
72 }
73
74 static void gdlm_bast(void *arg, int mode)
75 {
76         struct gfs2_glock *gl = arg;
77
78         switch (mode) {
79         case DLM_LOCK_EX:
80                 gfs2_glock_cb(gl, LM_ST_UNLOCKED);
81                 break;
82         case DLM_LOCK_CW:
83                 gfs2_glock_cb(gl, LM_ST_DEFERRED);
84                 break;
85         case DLM_LOCK_PR:
86                 gfs2_glock_cb(gl, LM_ST_SHARED);
87                 break;
88         default:
89                 printk(KERN_ERR "unknown bast mode %d", mode);
90                 BUG();
91         }
92 }
93
94 /* convert gfs lock-state to dlm lock-mode */
95
96 static int make_mode(const unsigned int lmstate)
97 {
98         switch (lmstate) {
99         case LM_ST_UNLOCKED:
100                 return DLM_LOCK_NL;
101         case LM_ST_EXCLUSIVE:
102                 return DLM_LOCK_EX;
103         case LM_ST_DEFERRED:
104                 return DLM_LOCK_CW;
105         case LM_ST_SHARED:
106                 return DLM_LOCK_PR;
107         }
108         printk(KERN_ERR "unknown LM state %d", lmstate);
109         BUG();
110         return -1;
111 }
112
113 static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
114                       const int req)
115 {
116         u32 lkf = 0;
117
118         if (gfs_flags & LM_FLAG_TRY)
119                 lkf |= DLM_LKF_NOQUEUE;
120
121         if (gfs_flags & LM_FLAG_TRY_1CB) {
122                 lkf |= DLM_LKF_NOQUEUE;
123                 lkf |= DLM_LKF_NOQUEUEBAST;
124         }
125
126         if (gfs_flags & LM_FLAG_PRIORITY) {
127                 lkf |= DLM_LKF_NOORDER;
128                 lkf |= DLM_LKF_HEADQUE;
129         }
130
131         if (gfs_flags & LM_FLAG_ANY) {
132                 if (req == DLM_LOCK_PR)
133                         lkf |= DLM_LKF_ALTCW;
134                 else if (req == DLM_LOCK_CW)
135                         lkf |= DLM_LKF_ALTPR;
136                 else
137                         BUG();
138         }
139
140         if (lkid != 0) 
141                 lkf |= DLM_LKF_CONVERT;
142
143         lkf |= DLM_LKF_VALBLK;
144
145         return lkf;
146 }
147
148 static unsigned int gdlm_lock(struct gfs2_glock *gl,
149                               unsigned int req_state, unsigned int flags)
150 {
151         struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
152         int error;
153         int req;
154         u32 lkf;
155
156         gl->gl_req = req_state;
157         req = make_mode(req_state);
158         lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
159
160         /*
161          * Submit the actual lock request.
162          */
163
164         error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
165                          GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
166         if (error == -EAGAIN)
167                 return 0;
168         if (error)
169                 return LM_OUT_ERROR;
170         return LM_OUT_ASYNC;
171 }
172
173 static void gdlm_put_lock(struct kmem_cache *cachep, struct gfs2_glock *gl)
174 {
175         struct gfs2_sbd *sdp = gl->gl_sbd;
176         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
177         int error;
178
179         if (gl->gl_lksb.sb_lkid == 0) {
180                 kmem_cache_free(cachep, gl);
181                 if (atomic_dec_and_test(&sdp->sd_glock_disposal))
182                         wake_up(&sdp->sd_glock_wait);
183                 return;
184         }
185
186         error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
187                            NULL, gl);
188         if (error) {
189                 printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n",
190                        gl->gl_name.ln_type,
191                        (unsigned long long)gl->gl_name.ln_number, error);
192                 return;
193         }
194 }
195
196 static void gdlm_cancel(struct gfs2_glock *gl)
197 {
198         struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
199         dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
200 }
201
202 static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
203 {
204         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
205         int error;
206
207         if (fsname == NULL) {
208                 fs_info(sdp, "no fsname found\n");
209                 return -EINVAL;
210         }
211
212         error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm,
213                                   DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
214                                   (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
215                                   GDLM_LVB_SIZE);
216         if (error)
217                 printk(KERN_ERR "dlm_new_lockspace error %d", error);
218
219         return error;
220 }
221
222 static void gdlm_unmount(struct gfs2_sbd *sdp)
223 {
224         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
225
226         if (ls->ls_dlm) {
227                 dlm_release_lockspace(ls->ls_dlm, 2);
228                 ls->ls_dlm = NULL;
229         }
230 }
231
232 static const match_table_t dlm_tokens = {
233         { Opt_jid, "jid=%d"},
234         { Opt_id, "id=%d"},
235         { Opt_first, "first=%d"},
236         { Opt_nodir, "nodir=%d"},
237         { Opt_err, NULL },
238 };
239
240 const struct lm_lockops gfs2_dlm_ops = {
241         .lm_proto_name = "lock_dlm",
242         .lm_mount = gdlm_mount,
243         .lm_unmount = gdlm_unmount,
244         .lm_put_lock = gdlm_put_lock,
245         .lm_lock = gdlm_lock,
246         .lm_cancel = gdlm_cancel,
247         .lm_tokens = &dlm_tokens,
248 };
249