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