aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/stackglue.h
blob: 1ec56fdb8d0d91752682bc532132dc6ae9cc029b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * stackglue.h
 *
 * Glue to the underlying cluster 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.
 */


#ifndef STACKGLUE_H
#define STACKGLUE_H

#include <linux/types.h>
#include <linux/list.h>
#include <linux/dlmconstants.h>

#include "dlm/dlmapi.h"
#include <linux/dlm.h>

/* Needed for plock-related prototypes */
struct file;
struct file_lock;

/*
 * dlmconstants.h does not have a LOCAL flag.  We hope to remove it
 * some day, but right now we need it.  Let's fake it.  This value is larger
 * than any flag in dlmconstants.h.
 */
#define DLM_LKF_LOCAL		0x00100000

/*
 * This shadows DLM_LOCKSPACE_LEN in fs/dlm/dlm_internal.h.  That probably
 * wants to be in a public header.
 */
#define GROUP_NAME_MAX		64


/*
 * ocfs2_protocol_version changes when ocfs2 does something different in
 * its inter-node behavior.  See dlmglue.c for more information.
 */
struct ocfs2_protocol_version {
	u8 pv_major;
	u8 pv_minor;
};

/*
 * The dlm_lockstatus struct includes lvb space, but the dlm_lksb struct only
 * has a pointer to separately allocated lvb space.  This struct exists only to
 * include in the lksb union to make space for a combined dlm_lksb and lvb.
 */
struct fsdlm_lksb_plus_lvb {
	struct dlm_lksb lksb;
	char lvb[DLM_LVB_LEN];
};

/*
 * A union of all lock status structures.  We define it here so that the
 * size of the union is known.  Lock status structures are embedded in
 * ocfs2 inodes.
 */
struct ocfs2_cluster_connection;
struct ocfs2_dlm_lksb {
	 union {
		 struct dlm_lockstatus lksb_o2dlm;
		 struct dlm_lksb lksb_fsdlm;
		 struct fsdlm_lksb_plus_lvb padding;
	 };
	 struct ocfs2_cluster_connection *lksb_conn;
};

/*
 * The ocfs2_locking_protocol defines the handlers called on ocfs2's behalf.
 */
struct ocfs2_locking_protocol {
	struct ocfs2_protocol_version lp_max_version;
	void (*lp_lock_ast)(struct ocfs2_dlm_lksb *lksb);
	void (*lp_blocking_ast)(struct ocfs2_dlm_lksb *lksb, int level);
	void (*lp_unlock_ast)(struct ocfs2_dlm_lksb *lksb, int error);
};


/*
 * A cluster connection.  Mostly opaque to ocfs2, the connection holds
 * state for the underlying stack.  ocfs2 does use cc_version to determine
 * locking compatibility.
 */
struct ocfs2_cluster_connection {
	char cc_name[GROUP_NAME_MAX];
	int cc_namelen;
	struct ocfs2_protocol_version cc_version;
	struct ocfs2_locking_protocol *cc_proto;
	void (*cc_recovery_handler)(int node_num, void *recovery_data);
	void *cc_recovery_data;
	void *cc_lockspace;
	void *cc_private;
};

/*
 * Each cluster stack implements the stack operations structure.  Not used
 * in the ocfs2 code, the stackglue code translates generic cluster calls
 * into stack operations.
 */
struct ocfs2_stack_operations {
	/*
	 * The fs code calls ocfs2_cluster_connect() to attach a new
	 * filesystem to the cluster stack.  The ->connect() op is passed
	 * an ocfs2_cluster_connection with the name and recovery field
	 * filled in.
	 *
	 * The stack must set up any notification mechanisms and create
	 * the filesystem lockspace in the DLM.  The lockspace should be
	 * stored on cc_lockspace.  Any other information can be stored on
	 * cc_private.
	 *
	 * ->connect() must not return until it is guaranteed that
	 *
	 *  - Node down notifications for the filesystem will be received
	 *    and passed to conn->cc_recovery_handler().
	 *  - Locking requests for the filesystem will be processed.
	 */
	int (*connect)(struct ocfs2_cluster_connection *conn);

	/*
	 * The fs code calls ocfs2_cluster_disconnect() when a filesystem
	 * no longer needs cluster services.  All DLM locks have been
	 * dropped, and recovery notification is being ignored by the
	 * fs code.  The stack must disengage from the DLM and discontinue
	 * recovery notification.
	 *
	 * Once ->disconnect() has returned, the connection structure will
	 * be freed.  Thus, a stack must not return from ->disconnect()
	 * until it will no longer reference the conn pointer.
	 *
	 * Once this call returns, the stack glue will be dropping this
	 * connection's reference on the module.
	 */
	int (*disconnect)(struct ocfs2_cluster_connection *conn);

	/*
	 * ->this_node() returns the cluster's unique identifier for the
	 * local node.
	 */
	int (*this_node)(unsigned int *node);

	/*
	 * Call the underlying dlm lock function.  The ->dlm_lock()
	 * callback should convert the flags and mode as appropriate.
	 *
	 * ast and bast functions are not part of the call because the
	 * stack will likely want to wrap ast and bast calls before passing
	 * them to stack->sp_proto.  There is no astarg.  The lksb will
	 * be passed back to the ast and bast functions.  The caller can
	 * use this to find their object.
	 */
	int (*dlm_lock)(struct ocfs2_cluster_connection *conn,
			int mode,
			struct ocfs2_dlm_lksb *lksb,
			u32 flags,
			void *name,
			unsigned int namelen);

	/*
	 * Call the underlying dlm unlock function.  The ->dlm_unlock()
	 * function should convert the flags as appropriate.
	 *
	 * The unlock ast is not passed, as the stack will want to wrap
	 * it before calling stack->sp_proto->lp_unlock_ast().  There is
	 * no astarg.  The lksb will be passed back to the unlock ast
	 * function.  The caller can use this to find their object.
	 */
	int (*dlm_unlock)(struct ocfs2_cluster_connection *conn,
			  struct ocfs2_dlm_lksb *lksb,
			  u32 flags);

	/*
	 * Return the status of the current lock status block.  The fs
	 * code should never dereference the union.  The ->lock_status()
	 * callback pulls out the stack-specific lksb, converts the status
	 * to a proper errno, and returns it.
	 */
	int (*lock_status)(struct ocfs2_dlm_lksb *lksb);

	/*
	 * Return non-zero if the LVB is valid.
	 */
	int (*lvb_valid)(struct ocfs2_dlm_lksb *lksb);

	/*
	 * Pull the lvb pointer off of the stack-specific lksb.
	 */
	void *(*lock_lvb)(struct ocfs2_dlm_lksb *lksb);

	/*
	 * Cluster-aware posix locks
	 *
	 * This is NULL for stacks which do not support posix locks.
	 */
	int (*plock)(struct ocfs2_cluster_connection *conn,
		     u64 ino,
		     struct file *file,
		     int cmd,
		     struct file_lock *fl);

	/*
	 * This is an optoinal debugging hook.  If provided, the
	 * stack can dump debugging information about this lock.
	 */
	void (*dump_lksb)(struct ocfs2_dlm_lksb *lksb);
};

/*
 * Each stack plugin must describe itself by registering a
 * ocfs2_stack_plugin structure.  This is only seen by stackglue and the
 * stack driver.
 */
struct ocfs2_stack_plugin {
	char *sp_name;
	struct ocfs2_stack_operations *sp_ops;
	struct module *sp_owner;

	/* These are managed by the stackglue code. */
	struct list_head sp_list;
	unsigned int sp_count;
	struct ocfs2_protocol_version sp_max_proto;
};


/* Used by the filesystem */
int ocfs2_cluster_connect(const char *stack_name,
			  const char *group,
			  int grouplen,
			  struct ocfs2_locking_protocol *lproto,
			  void (*recovery_handler)(int node_num,
						   void *recovery_data),
			  void *recovery_data,
			  struct ocfs2_cluster_connection **conn);
/*
 * Used by callers that don't store their stack name.  They must ensure
 * all nodes have the same stack.
 */
int ocfs2_cluster_connect_agnostic(const char *group,
				   int grouplen,
				   struct ocfs2_locking_protocol *lproto,
				   void (*recovery_handler)(int node_num,
							    void *recovery_data),
				   void *recovery_data,
				   struct ocfs2_cluster_connection **conn);
int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,
			     int hangup_pending);
void ocfs2_cluster_hangup(const char *group, int grouplen);
int ocfs2_cluster_this_node(unsigned int *node);

struct ocfs2_lock_res;
int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn,
		   int mode,
		   struct ocfs2_dlm_lksb *lksb,
		   u32 flags,
		   void *name,
		   unsigned int namelen);
int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,
		     struct ocfs2_dlm_lksb *lksb,
		     u32 flags);

int ocfs2_dlm_lock_status(struct ocfs2_dlm_lksb *lksb);
int ocfs2_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb);
void *ocfs2_dlm_lvb(struct ocfs2_dlm_lksb *lksb);
void ocfs2_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb);

int ocfs2_stack_supports_plocks(void);
int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
		struct file *file, int cmd, struct file_lock *fl);

void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_proto);


/* Used by stack plugins */
int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);

#endif  /* STACKGLUE_H */