Blame view

fs/ocfs2/stack_o2cb.c 9.9 KB
e3dad42bf   Joel Becker   ocfs2: Create ocf...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /* -*- mode: c; c-basic-offset: 8; -*-
   * vim: noexpandtab sw=8 ts=8 sts=0:
   *
   * stack_o2cb.c
   *
   * Code which interfaces ocfs2 with the o2cb stack.
   *
   * Copyright (C) 2007 Oracle.  All rights reserved.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public
   * License as published by the Free Software Foundation, version 2.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   */
8a57a9dda   Roel Kluin   ocfs2: keep index...
19
  #include <linux/kernel.h>
e3dad42bf   Joel Becker   ocfs2: Create ocf...
20
  #include <linux/crc32.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
286eaa95c   Joel Becker   ocfs2: Break out ...
22
  #include <linux/module.h>
e3dad42bf   Joel Becker   ocfs2: Create ocf...
23
24
25
26
27
28
29
30
31
32
33
34
35
  
  /* Needed for AOP_TRUNCATED_PAGE in mlog_errno() */
  #include <linux/fs.h>
  
  #include "cluster/masklog.h"
  #include "cluster/nodemanager.h"
  #include "cluster/heartbeat.h"
  
  #include "stackglue.h"
  
  struct o2dlm_private {
  	struct dlm_eviction_cb op_eviction_cb;
  };
286eaa95c   Joel Becker   ocfs2: Break out ...
36
  static struct ocfs2_stack_plugin o2cb_stack;
e3dad42bf   Joel Becker   ocfs2: Create ocf...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  /* These should be identical */
  #if (DLM_LOCK_IV != LKM_IVMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_NL != LKM_NLMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_CR != LKM_CRMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_CW != LKM_CWMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_PR != LKM_PRMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_PW != LKM_PWMODE)
  # error Lock modes do not match
  #endif
  #if (DLM_LOCK_EX != LKM_EXMODE)
  # error Lock modes do not match
  #endif
  static inline int mode_to_o2dlm(int mode)
  {
  	BUG_ON(mode > LKM_MAXMODE);
  
  	return mode;
  }
  
  #define map_flag(_generic, _o2dlm)		\
  	if (flags & (_generic)) {		\
  		flags &= ~(_generic);		\
  		o2dlm_flags |= (_o2dlm);	\
  	}
  static int flags_to_o2dlm(u32 flags)
  {
  	int o2dlm_flags = 0;
  
  	map_flag(DLM_LKF_NOQUEUE, LKM_NOQUEUE);
  	map_flag(DLM_LKF_CANCEL, LKM_CANCEL);
  	map_flag(DLM_LKF_CONVERT, LKM_CONVERT);
  	map_flag(DLM_LKF_VALBLK, LKM_VALBLK);
  	map_flag(DLM_LKF_IVVALBLK, LKM_INVVALBLK);
  	map_flag(DLM_LKF_ORPHAN, LKM_ORPHAN);
  	map_flag(DLM_LKF_FORCEUNLOCK, LKM_FORCE);
  	map_flag(DLM_LKF_TIMEOUT, LKM_TIMEOUT);
  	map_flag(DLM_LKF_LOCAL, LKM_LOCAL);
  
  	/* map_flag() should have cleared every flag passed in */
  	BUG_ON(flags != 0);
  
  	return o2dlm_flags;
  }
  #undef map_flag
  
  /*
   * Map an o2dlm status to standard errno values.
   *
   * o2dlm only uses a handful of these, and returns even fewer to the
   * caller. Still, we try to assign sane values to each error.
   *
   * The following value pairs have special meanings to dlmglue, thus
   * the right hand side needs to stay unique - never duplicate the
   * mapping elsewhere in the table!
   *
   * DLM_NORMAL:		0
   * DLM_NOTQUEUED:	-EAGAIN
   * DLM_CANCELGRANT:	-EBUSY
   * DLM_CANCEL:		-DLM_ECANCEL
   */
  /* Keep in sync with dlmapi.h */
  static int status_map[] = {
  	[DLM_NORMAL]			= 0,		/* Success */
  	[DLM_GRANTED]			= -EINVAL,
  	[DLM_DENIED]			= -EACCES,
  	[DLM_DENIED_NOLOCKS]		= -EACCES,
  	[DLM_WORKING]			= -EACCES,
  	[DLM_BLOCKED]			= -EINVAL,
  	[DLM_BLOCKED_ORPHAN]		= -EINVAL,
  	[DLM_DENIED_GRACE_PERIOD]	= -EACCES,
  	[DLM_SYSERR]			= -ENOMEM,	/* It is what it is */
  	[DLM_NOSUPPORT]			= -EPROTO,
  	[DLM_CANCELGRANT]		= -EBUSY,	/* Cancel after grant */
  	[DLM_IVLOCKID]			= -EINVAL,
  	[DLM_SYNC]			= -EINVAL,
  	[DLM_BADTYPE]			= -EINVAL,
  	[DLM_BADRESOURCE]		= -EINVAL,
  	[DLM_MAXHANDLES]		= -ENOMEM,
  	[DLM_NOCLINFO]			= -EINVAL,
  	[DLM_NOLOCKMGR]			= -EINVAL,
  	[DLM_NOPURGED]			= -EINVAL,
  	[DLM_BADARGS]			= -EINVAL,
  	[DLM_VOID]			= -EINVAL,
  	[DLM_NOTQUEUED]			= -EAGAIN,	/* Trylock failed */
  	[DLM_IVBUFLEN]			= -EINVAL,
  	[DLM_CVTUNGRANT]		= -EPERM,
  	[DLM_BADPARAM]			= -EINVAL,
  	[DLM_VALNOTVALID]		= -EINVAL,
  	[DLM_REJECTED]			= -EPERM,
  	[DLM_ABORT]			= -EINVAL,
  	[DLM_CANCEL]			= -DLM_ECANCEL,	/* Successful cancel */
  	[DLM_IVRESHANDLE]		= -EINVAL,
  	[DLM_DEADLOCK]			= -EDEADLK,
  	[DLM_DENIED_NOASTS]		= -EINVAL,
  	[DLM_FORWARD]			= -EINVAL,
  	[DLM_TIMEOUT]			= -ETIMEDOUT,
  	[DLM_IVGROUPID]			= -EINVAL,
  	[DLM_VERS_CONFLICT]		= -EOPNOTSUPP,
  	[DLM_BAD_DEVICE_PATH]		= -ENOENT,
  	[DLM_NO_DEVICE_PERMISSION]	= -EPERM,
  	[DLM_NO_CONTROL_DEVICE]		= -ENOENT,
  	[DLM_RECOVERING]		= -ENOTCONN,
  	[DLM_MIGRATING]			= -ERESTART,
  	[DLM_MAXSTATS]			= -EINVAL,
  };
  
  static int dlm_status_to_errno(enum dlm_status status)
  {
8a57a9dda   Roel Kluin   ocfs2: keep index...
155
  	BUG_ON(status < 0 || status >= ARRAY_SIZE(status_map));
e3dad42bf   Joel Becker   ocfs2: Create ocf...
156
157
158
159
160
161
  
  	return status_map[status];
  }
  
  static void o2dlm_lock_ast_wrapper(void *astarg)
  {
c0e413385   Joel Becker   ocfs2: Attach the...
162
  	struct ocfs2_dlm_lksb *lksb = astarg;
a796d2862   Joel Becker   ocfs2: Pass lksbs...
163

110946c8f   Joel Becker   ocfs2: Hang the l...
164
  	lksb->lksb_conn->cc_proto->lp_lock_ast(lksb);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
165
166
167
168
  }
  
  static void o2dlm_blocking_ast_wrapper(void *astarg, int level)
  {
c0e413385   Joel Becker   ocfs2: Attach the...
169
  	struct ocfs2_dlm_lksb *lksb = astarg;
a796d2862   Joel Becker   ocfs2: Pass lksbs...
170

110946c8f   Joel Becker   ocfs2: Hang the l...
171
  	lksb->lksb_conn->cc_proto->lp_blocking_ast(lksb, level);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
172
173
174
175
  }
  
  static void o2dlm_unlock_ast_wrapper(void *astarg, enum dlm_status status)
  {
c0e413385   Joel Becker   ocfs2: Attach the...
176
  	struct ocfs2_dlm_lksb *lksb = astarg;
e3dad42bf   Joel Becker   ocfs2: Create ocf...
177
  	int error = dlm_status_to_errno(status);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
178
179
180
181
182
183
184
185
186
187
188
189
190
  	/*
  	 * In o2dlm, you can get both the lock_ast() for the lock being
  	 * granted and the unlock_ast() for the CANCEL failing.  A
  	 * successful cancel sends DLM_NORMAL here.  If the
  	 * lock grant happened before the cancel arrived, you get
  	 * DLM_CANCELGRANT.
  	 *
  	 * There's no need for the double-ast.  If we see DLM_CANCELGRANT,
  	 * we just ignore it.  We expect the lock_ast() to handle the
  	 * granted lock.
  	 */
  	if (status == DLM_CANCELGRANT)
  		return;
110946c8f   Joel Becker   ocfs2: Hang the l...
191
  	lksb->lksb_conn->cc_proto->lp_unlock_ast(lksb, error);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
192
193
194
195
  }
  
  static int o2cb_dlm_lock(struct ocfs2_cluster_connection *conn,
  			 int mode,
c0e413385   Joel Becker   ocfs2: Attach the...
196
  			 struct ocfs2_dlm_lksb *lksb,
e3dad42bf   Joel Becker   ocfs2: Create ocf...
197
198
  			 u32 flags,
  			 void *name,
a796d2862   Joel Becker   ocfs2: Pass lksbs...
199
  			 unsigned int namelen)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
200
201
202
203
204
205
206
207
  {
  	enum dlm_status status;
  	int o2dlm_mode = mode_to_o2dlm(mode);
  	int o2dlm_flags = flags_to_o2dlm(flags);
  	int ret;
  
  	status = dlmlock(conn->cc_lockspace, o2dlm_mode, &lksb->lksb_o2dlm,
  			 o2dlm_flags, name, namelen,
a796d2862   Joel Becker   ocfs2: Pass lksbs...
208
  			 o2dlm_lock_ast_wrapper, lksb,
e3dad42bf   Joel Becker   ocfs2: Create ocf...
209
210
211
212
213
214
  			 o2dlm_blocking_ast_wrapper);
  	ret = dlm_status_to_errno(status);
  	return ret;
  }
  
  static int o2cb_dlm_unlock(struct ocfs2_cluster_connection *conn,
c0e413385   Joel Becker   ocfs2: Attach the...
215
  			   struct ocfs2_dlm_lksb *lksb,
a796d2862   Joel Becker   ocfs2: Pass lksbs...
216
  			   u32 flags)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
217
218
219
220
221
222
  {
  	enum dlm_status status;
  	int o2dlm_flags = flags_to_o2dlm(flags);
  	int ret;
  
  	status = dlmunlock(conn->cc_lockspace, &lksb->lksb_o2dlm,
a796d2862   Joel Becker   ocfs2: Pass lksbs...
223
  			   o2dlm_flags, o2dlm_unlock_ast_wrapper, lksb);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
224
225
226
  	ret = dlm_status_to_errno(status);
  	return ret;
  }
c0e413385   Joel Becker   ocfs2: Attach the...
227
  static int o2cb_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
228
229
230
  {
  	return dlm_status_to_errno(lksb->lksb_o2dlm.status);
  }
1c520dfbf   Joel Becker   ocfs2: Provide th...
231
232
233
234
235
  /*
   * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB
   * contents, it will zero out the LVB.  Thus the caller can always trust
   * the contents.
   */
c0e413385   Joel Becker   ocfs2: Attach the...
236
  static int o2cb_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
1c520dfbf   Joel Becker   ocfs2: Provide th...
237
238
239
  {
  	return 1;
  }
c0e413385   Joel Becker   ocfs2: Attach the...
240
  static void *o2cb_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
241
242
243
  {
  	return (void *)(lksb->lksb_o2dlm.lvb);
  }
c0e413385   Joel Becker   ocfs2: Attach the...
244
  static void o2cb_dump_lksb(struct ocfs2_dlm_lksb *lksb)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  {
  	dlm_print_one_lock(lksb->lksb_o2dlm.lockid);
  }
  
  /*
   * Called from the dlm when it's about to evict a node. This is how the
   * classic stack signals node death.
   */
  static void o2dlm_eviction_cb(int node_num, void *data)
  {
  	struct ocfs2_cluster_connection *conn = data;
  
  	mlog(ML_NOTICE, "o2dlm has evicted node %d from group %.*s
  ",
  	     node_num, conn->cc_namelen, conn->cc_name);
  
  	conn->cc_recovery_handler(node_num, conn->cc_recovery_data);
  }
  
  static int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn)
  {
  	int rc = 0;
  	u32 dlm_key;
  	struct dlm_ctxt *dlm;
  	struct o2dlm_private *priv;
e5f2cb2b1   Wengang Wang   ocfs2: fix a misl...
270
  	struct dlm_protocol_version fs_version;
e3dad42bf   Joel Becker   ocfs2: Create ocf...
271
272
  
  	BUG_ON(conn == NULL);
110946c8f   Joel Becker   ocfs2: Hang the l...
273
  	BUG_ON(conn->cc_proto == NULL);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
274
275
276
277
  
  	/* for now we only have one cluster/node, make sure we see it
  	 * in the heartbeat universe */
  	if (!o2hb_check_local_node_heartbeating()) {
5f3c6d9c6   Sunil Mushran   (5f3c6d9c61577070...
278
279
280
  		if (o2hb_global_heartbeat_active())
  			mlog(ML_ERROR, "Global heartbeat not started
  ");
e3dad42bf   Joel Becker   ocfs2: Create ocf...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  		rc = -EINVAL;
  		goto out;
  	}
  
  	priv = kzalloc(sizeof(struct o2dlm_private), GFP_KERNEL);
  	if (!priv) {
  		rc = -ENOMEM;
  		goto out_free;
  	}
  
  	/* This just fills the structure in.  It is safe to pass conn. */
  	dlm_setup_eviction_cb(&priv->op_eviction_cb, o2dlm_eviction_cb,
  			      conn);
  
  	conn->cc_private = priv;
  
  	/* used by the dlm code to make message headers unique, each
  	 * node in this domain must agree on this. */
  	dlm_key = crc32_le(0, conn->cc_name, conn->cc_namelen);
e5f2cb2b1   Wengang Wang   ocfs2: fix a misl...
300
301
  	fs_version.pv_major = conn->cc_version.pv_major;
  	fs_version.pv_minor = conn->cc_version.pv_minor;
e3dad42bf   Joel Becker   ocfs2: Create ocf...
302

e5f2cb2b1   Wengang Wang   ocfs2: fix a misl...
303
  	dlm = dlm_register_domain(conn->cc_name, dlm_key, &fs_version);
e3dad42bf   Joel Becker   ocfs2: Create ocf...
304
305
306
307
308
  	if (IS_ERR(dlm)) {
  		rc = PTR_ERR(dlm);
  		mlog_errno(rc);
  		goto out_free;
  	}
e5f2cb2b1   Wengang Wang   ocfs2: fix a misl...
309
310
  	conn->cc_version.pv_major = fs_version.pv_major;
  	conn->cc_version.pv_minor = fs_version.pv_minor;
e3dad42bf   Joel Becker   ocfs2: Create ocf...
311
312
313
314
315
316
317
318
319
320
321
  	conn->cc_lockspace = dlm;
  
  	dlm_register_eviction_cb(dlm, &priv->op_eviction_cb);
  
  out_free:
  	if (rc && conn->cc_private)
  		kfree(conn->cc_private);
  
  out:
  	return rc;
  }
2c39450b3   Joel Becker   ocfs2: Remove ->h...
322
  static int o2cb_cluster_disconnect(struct ocfs2_cluster_connection *conn)
e3dad42bf   Joel Becker   ocfs2: Create ocf...
323
324
325
326
327
328
329
330
331
332
333
334
335
  {
  	struct dlm_ctxt *dlm = conn->cc_lockspace;
  	struct o2dlm_private *priv = conn->cc_private;
  
  	dlm_unregister_eviction_cb(&priv->op_eviction_cb);
  	conn->cc_private = NULL;
  	kfree(priv);
  
  	dlm_unregister_domain(dlm);
  	conn->cc_lockspace = NULL;
  
  	return 0;
  }
e3dad42bf   Joel Becker   ocfs2: Create ocf...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  static int o2cb_cluster_this_node(unsigned int *node)
  {
  	int node_num;
  
  	node_num = o2nm_this_node();
  	if (node_num == O2NM_INVALID_NODE_NUM)
  		return -ENOENT;
  
  	if (node_num >= O2NM_MAX_NODES)
  		return -EOVERFLOW;
  
  	*node = node_num;
  	return 0;
  }
4af694e67   Adrian Bunk   ocfs2: make struc...
350
  static struct ocfs2_stack_operations o2cb_stack_ops = {
e3dad42bf   Joel Becker   ocfs2: Create ocf...
351
352
  	.connect	= o2cb_cluster_connect,
  	.disconnect	= o2cb_cluster_disconnect,
e3dad42bf   Joel Becker   ocfs2: Create ocf...
353
354
355
356
  	.this_node	= o2cb_cluster_this_node,
  	.dlm_lock	= o2cb_dlm_lock,
  	.dlm_unlock	= o2cb_dlm_unlock,
  	.lock_status	= o2cb_dlm_lock_status,
1c520dfbf   Joel Becker   ocfs2: Provide th...
357
  	.lvb_valid	= o2cb_dlm_lvb_valid,
e3dad42bf   Joel Becker   ocfs2: Create ocf...
358
359
360
  	.lock_lvb	= o2cb_dlm_lvb,
  	.dump_lksb	= o2cb_dump_lksb,
  };
286eaa95c   Joel Becker   ocfs2: Break out ...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  static struct ocfs2_stack_plugin o2cb_stack = {
  	.sp_name	= "o2cb",
  	.sp_ops		= &o2cb_stack_ops,
  	.sp_owner	= THIS_MODULE,
  };
  
  static int __init o2cb_stack_init(void)
  {
  	return ocfs2_stack_glue_register(&o2cb_stack);
  }
  
  static void __exit o2cb_stack_exit(void)
  {
  	ocfs2_stack_glue_unregister(&o2cb_stack);
  }
  
  MODULE_AUTHOR("Oracle");
  MODULE_DESCRIPTION("ocfs2 driver for the classic o2cb stack");
  MODULE_LICENSE("GPL");
  module_init(o2cb_stack_init);
  module_exit(o2cb_stack_exit);