xref: /openbmc/linux/fs/ocfs2/stack_user.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fa60ce2cSMasahiro Yamada /*
38adf0536SJoel Becker  * stack_user.c
48adf0536SJoel Becker  *
58adf0536SJoel Becker  * Code which interfaces ocfs2 with fs/dlm and a userspace stack.
68adf0536SJoel Becker  *
78adf0536SJoel Becker  * Copyright (C) 2007 Oracle.  All rights reserved.
88adf0536SJoel Becker  */
98adf0536SJoel Becker 
108adf0536SJoel Becker #include <linux/module.h>
116427a727SJoel Becker #include <linux/fs.h>
125970e15dSJeff Layton #include <linux/filelock.h>
136427a727SJoel Becker #include <linux/miscdevice.h>
146427a727SJoel Becker #include <linux/mutex.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
166427a727SJoel Becker #include <linux/reboot.h>
17c994c2ebSGoldwyn Rodrigues #include <linux/sched.h>
187c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
198adf0536SJoel Becker 
208adf0536SJoel Becker #include "stackglue.h"
218adf0536SJoel Becker 
2253da4939SMark Fasheh #include <linux/dlm_plock.h>
238adf0536SJoel Becker 
246427a727SJoel Becker /*
256427a727SJoel Becker  * The control protocol starts with a handshake.  Until the handshake
266427a727SJoel Becker  * is complete, the control device will fail all write(2)s.
276427a727SJoel Becker  *
286427a727SJoel Becker  * The handshake is simple.  First, the client reads until EOF.  Each line
296427a727SJoel Becker  * of output is a supported protocol tag.  All protocol tags are a single
306427a727SJoel Becker  * character followed by a two hex digit version number.  Currently the
316427a727SJoel Becker  * only things supported is T01, for "Text-base version 0x01".  Next, the
32de870ef0SJoel Becker  * client writes the version they would like to use, including the newline.
33de870ef0SJoel Becker  * Thus, the protocol tag is 'T01\n'.  If the version tag written is
34de870ef0SJoel Becker  * unknown, -EINVAL is returned.  Once the negotiation is complete, the
35de870ef0SJoel Becker  * client can start sending messages.
36de870ef0SJoel Becker  *
37d4b95eefSJoel Becker  * The T01 protocol has three messages.  First is the "SETN" message.
383cfd4ab6SJoel Becker  * It has the following syntax:
393cfd4ab6SJoel Becker  *
403cfd4ab6SJoel Becker  *  SETN<space><8-char-hex-nodenum><newline>
413cfd4ab6SJoel Becker  *
423cfd4ab6SJoel Becker  * This is 14 characters.
433cfd4ab6SJoel Becker  *
443cfd4ab6SJoel Becker  * The "SETN" message must be the first message following the protocol.
453cfd4ab6SJoel Becker  * It tells ocfs2_control the local node number.
463cfd4ab6SJoel Becker  *
47d4b95eefSJoel Becker  * Next comes the "SETV" message.  It has the following syntax:
48d4b95eefSJoel Becker  *
49d4b95eefSJoel Becker  *  SETV<space><2-char-hex-major><space><2-char-hex-minor><newline>
50d4b95eefSJoel Becker  *
51d4b95eefSJoel Becker  * This is 11 characters.
52d4b95eefSJoel Becker  *
53d4b95eefSJoel Becker  * The "SETV" message sets the filesystem locking protocol version as
54d4b95eefSJoel Becker  * negotiated by the client.  The client negotiates based on the maximum
55d4b95eefSJoel Becker  * version advertised in /sys/fs/ocfs2/max_locking_protocol.  The major
56d4b95eefSJoel Becker  * number from the "SETV" message must match
57e603cfb0SJoel Becker  * ocfs2_user_plugin.sp_max_proto.pv_major, and the minor number
58e603cfb0SJoel Becker  * must be less than or equal to ...sp_max_version.pv_minor.
59d4b95eefSJoel Becker  *
60d4b95eefSJoel Becker  * Once this information has been set, mounts will be allowed.  From this
61d4b95eefSJoel Becker  * point on, the "DOWN" message can be sent for node down notification.
62d4b95eefSJoel Becker  * It has the following syntax:
63de870ef0SJoel Becker  *
64de870ef0SJoel Becker  *  DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline>
65de870ef0SJoel Becker  *
66de870ef0SJoel Becker  * eg:
67de870ef0SJoel Becker  *
68de870ef0SJoel Becker  *  DOWN 632A924FDD844190BDA93C0DF6B94899 00000001\n
69de870ef0SJoel Becker  *
70de870ef0SJoel Becker  * This is 47 characters.
716427a727SJoel Becker  */
726427a727SJoel Becker 
736427a727SJoel Becker /*
74462c7e6aSJoel Becker  * Whether or not the client has done the handshake.
75462c7e6aSJoel Becker  * For now, we have just one protocol version.
76462c7e6aSJoel Becker  */
77462c7e6aSJoel Becker #define OCFS2_CONTROL_PROTO			"T01\n"
78462c7e6aSJoel Becker #define OCFS2_CONTROL_PROTO_LEN			4
793cfd4ab6SJoel Becker 
803cfd4ab6SJoel Becker /* Handshake states */
81462c7e6aSJoel Becker #define OCFS2_CONTROL_HANDSHAKE_INVALID		(0)
82462c7e6aSJoel Becker #define OCFS2_CONTROL_HANDSHAKE_READ		(1)
833cfd4ab6SJoel Becker #define OCFS2_CONTROL_HANDSHAKE_PROTOCOL	(2)
843cfd4ab6SJoel Becker #define OCFS2_CONTROL_HANDSHAKE_VALID		(3)
853cfd4ab6SJoel Becker 
863cfd4ab6SJoel Becker /* Messages */
873cfd4ab6SJoel Becker #define OCFS2_CONTROL_MESSAGE_OP_LEN		4
883cfd4ab6SJoel Becker #define OCFS2_CONTROL_MESSAGE_SETNODE_OP	"SETN"
893cfd4ab6SJoel Becker #define OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN	14
90d4b95eefSJoel Becker #define OCFS2_CONTROL_MESSAGE_SETVERSION_OP	"SETV"
91d4b95eefSJoel Becker #define OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN	11
923cfd4ab6SJoel Becker #define OCFS2_CONTROL_MESSAGE_DOWN_OP		"DOWN"
93de870ef0SJoel Becker #define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN	47
94de870ef0SJoel Becker #define OCFS2_TEXT_UUID_LEN			32
95d4b95eefSJoel Becker #define OCFS2_CONTROL_MESSAGE_VERNUM_LEN	2
96de870ef0SJoel Becker #define OCFS2_CONTROL_MESSAGE_NODENUM_LEN	8
9741503630SGoldwyn Rodrigues #define VERSION_LOCK				"version_lock"
98462c7e6aSJoel Becker 
993e834151SGoldwyn Rodrigues enum ocfs2_connection_type {
1003e834151SGoldwyn Rodrigues 	WITH_CONTROLD,
1013e834151SGoldwyn Rodrigues 	NO_CONTROLD
1023e834151SGoldwyn Rodrigues };
1033e834151SGoldwyn Rodrigues 
104462c7e6aSJoel Becker /*
1056427a727SJoel Becker  * ocfs2_live_connection is refcounted because the filesystem and
1066427a727SJoel Becker  * miscdevice sides can detach in different order.  Let's just be safe.
1076427a727SJoel Becker  */
1086427a727SJoel Becker struct ocfs2_live_connection {
1096427a727SJoel Becker 	struct list_head		oc_list;
1106427a727SJoel Becker 	struct ocfs2_cluster_connection	*oc_conn;
1113e834151SGoldwyn Rodrigues 	enum ocfs2_connection_type	oc_type;
11266e188fcSGoldwyn Rodrigues 	atomic_t                        oc_this_node;
11366e188fcSGoldwyn Rodrigues 	int                             oc_our_slot;
11441503630SGoldwyn Rodrigues 	struct dlm_lksb                 oc_version_lksb;
11541503630SGoldwyn Rodrigues 	char                            oc_lvb[DLM_LVB_LEN];
11641503630SGoldwyn Rodrigues 	struct completion               oc_sync_wait;
117c994c2ebSGoldwyn Rodrigues 	wait_queue_head_t		oc_wait;
1186427a727SJoel Becker };
1196427a727SJoel Becker 
120462c7e6aSJoel Becker struct ocfs2_control_private {
121462c7e6aSJoel Becker 	struct list_head op_list;
122462c7e6aSJoel Becker 	int op_state;
1233cfd4ab6SJoel Becker 	int op_this_node;
124d4b95eefSJoel Becker 	struct ocfs2_protocol_version op_proto;
1253cfd4ab6SJoel Becker };
1263cfd4ab6SJoel Becker 
1273cfd4ab6SJoel Becker /* SETN<space><8-char-hex-nodenum><newline> */
1283cfd4ab6SJoel Becker struct ocfs2_control_message_setn {
1293cfd4ab6SJoel Becker 	char	tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
1303cfd4ab6SJoel Becker 	char	space;
1313cfd4ab6SJoel Becker 	char	nodestr[OCFS2_CONTROL_MESSAGE_NODENUM_LEN];
1323cfd4ab6SJoel Becker 	char	newline;
1333cfd4ab6SJoel Becker };
1343cfd4ab6SJoel Becker 
135d4b95eefSJoel Becker /* SETV<space><2-char-hex-major><space><2-char-hex-minor><newline> */
136d4b95eefSJoel Becker struct ocfs2_control_message_setv {
137d4b95eefSJoel Becker 	char	tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
138d4b95eefSJoel Becker 	char	space1;
139d4b95eefSJoel Becker 	char	major[OCFS2_CONTROL_MESSAGE_VERNUM_LEN];
140d4b95eefSJoel Becker 	char	space2;
141d4b95eefSJoel Becker 	char	minor[OCFS2_CONTROL_MESSAGE_VERNUM_LEN];
142d4b95eefSJoel Becker 	char	newline;
143d4b95eefSJoel Becker };
144d4b95eefSJoel Becker 
1453cfd4ab6SJoel Becker /* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */
1463cfd4ab6SJoel Becker struct ocfs2_control_message_down {
1473cfd4ab6SJoel Becker 	char	tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
1483cfd4ab6SJoel Becker 	char	space1;
1493cfd4ab6SJoel Becker 	char	uuid[OCFS2_TEXT_UUID_LEN];
1503cfd4ab6SJoel Becker 	char	space2;
1513cfd4ab6SJoel Becker 	char	nodestr[OCFS2_CONTROL_MESSAGE_NODENUM_LEN];
1523cfd4ab6SJoel Becker 	char	newline;
1533cfd4ab6SJoel Becker };
1543cfd4ab6SJoel Becker 
1553cfd4ab6SJoel Becker union ocfs2_control_message {
1563cfd4ab6SJoel Becker 	char					tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
1573cfd4ab6SJoel Becker 	struct ocfs2_control_message_setn	u_setn;
158d4b95eefSJoel Becker 	struct ocfs2_control_message_setv	u_setv;
1593cfd4ab6SJoel Becker 	struct ocfs2_control_message_down	u_down;
160462c7e6aSJoel Becker };
161462c7e6aSJoel Becker 
162a12630b1SJoel Becker static struct ocfs2_stack_plugin ocfs2_user_plugin;
163cf4d8d75SDavid Teigland 
1646427a727SJoel Becker static atomic_t ocfs2_control_opened;
1653cfd4ab6SJoel Becker static int ocfs2_control_this_node = -1;
166d4b95eefSJoel Becker static struct ocfs2_protocol_version running_proto;
1676427a727SJoel Becker 
1686427a727SJoel Becker static LIST_HEAD(ocfs2_live_connection_list);
169462c7e6aSJoel Becker static LIST_HEAD(ocfs2_control_private_list);
1706427a727SJoel Becker static DEFINE_MUTEX(ocfs2_control_lock);
1716427a727SJoel Becker 
ocfs2_control_set_handshake_state(struct file * file,int state)172462c7e6aSJoel Becker static inline void ocfs2_control_set_handshake_state(struct file *file,
173462c7e6aSJoel Becker 						     int state)
174462c7e6aSJoel Becker {
175462c7e6aSJoel Becker 	struct ocfs2_control_private *p = file->private_data;
176462c7e6aSJoel Becker 	p->op_state = state;
177462c7e6aSJoel Becker }
178462c7e6aSJoel Becker 
ocfs2_control_get_handshake_state(struct file * file)179462c7e6aSJoel Becker static inline int ocfs2_control_get_handshake_state(struct file *file)
180462c7e6aSJoel Becker {
181462c7e6aSJoel Becker 	struct ocfs2_control_private *p = file->private_data;
182462c7e6aSJoel Becker 	return p->op_state;
183462c7e6aSJoel Becker }
184462c7e6aSJoel Becker 
ocfs2_connection_find(const char * name)1856427a727SJoel Becker static struct ocfs2_live_connection *ocfs2_connection_find(const char *name)
1866427a727SJoel Becker {
1876427a727SJoel Becker 	size_t len = strlen(name);
1886427a727SJoel Becker 	struct ocfs2_live_connection *c;
1896427a727SJoel Becker 
1906427a727SJoel Becker 	BUG_ON(!mutex_is_locked(&ocfs2_control_lock));
1916427a727SJoel Becker 
1926427a727SJoel Becker 	list_for_each_entry(c, &ocfs2_live_connection_list, oc_list) {
1936427a727SJoel Becker 		if ((c->oc_conn->cc_namelen == len) &&
1946427a727SJoel Becker 		    !strncmp(c->oc_conn->cc_name, name, len))
1956427a727SJoel Becker 			return c;
1966427a727SJoel Becker 	}
1976427a727SJoel Becker 
198226291aaSdann frazier 	return NULL;
1996427a727SJoel Becker }
2006427a727SJoel Becker 
2016427a727SJoel Becker /*
2026427a727SJoel Becker  * ocfs2_live_connection structures are created underneath the ocfs2
2036427a727SJoel Becker  * mount path.  Since the VFS prevents multiple calls to
2046427a727SJoel Becker  * fill_super(), we can't get dupes here.
2056427a727SJoel Becker  */
ocfs2_live_connection_attach(struct ocfs2_cluster_connection * conn,struct ocfs2_live_connection * c)20624aa3386SGoldwyn Rodrigues static int ocfs2_live_connection_attach(struct ocfs2_cluster_connection *conn,
20724aa3386SGoldwyn Rodrigues 				     struct ocfs2_live_connection *c)
2086427a727SJoel Becker {
2096427a727SJoel Becker 	int rc = 0;
2106427a727SJoel Becker 
2116427a727SJoel Becker 	mutex_lock(&ocfs2_control_lock);
2126427a727SJoel Becker 	c->oc_conn = conn;
2136427a727SJoel Becker 
214c994c2ebSGoldwyn Rodrigues 	if ((c->oc_type == NO_CONTROLD) || atomic_read(&ocfs2_control_opened))
2156427a727SJoel Becker 		list_add(&c->oc_list, &ocfs2_live_connection_list);
2166427a727SJoel Becker 	else {
2176427a727SJoel Becker 		printk(KERN_ERR
2186427a727SJoel Becker 		       "ocfs2: Userspace control daemon is not present\n");
2196427a727SJoel Becker 		rc = -ESRCH;
2206427a727SJoel Becker 	}
2216427a727SJoel Becker 
2226427a727SJoel Becker 	mutex_unlock(&ocfs2_control_lock);
2236427a727SJoel Becker 	return rc;
2246427a727SJoel Becker }
2256427a727SJoel Becker 
2266427a727SJoel Becker /*
2276427a727SJoel Becker  * This function disconnects the cluster connection from ocfs2_control.
2286427a727SJoel Becker  * Afterwards, userspace can't affect the cluster connection.
2296427a727SJoel Becker  */
ocfs2_live_connection_drop(struct ocfs2_live_connection * c)2306427a727SJoel Becker static void ocfs2_live_connection_drop(struct ocfs2_live_connection *c)
2316427a727SJoel Becker {
2326427a727SJoel Becker 	mutex_lock(&ocfs2_control_lock);
2336427a727SJoel Becker 	list_del_init(&c->oc_list);
2346427a727SJoel Becker 	c->oc_conn = NULL;
2356427a727SJoel Becker 	mutex_unlock(&ocfs2_control_lock);
2366427a727SJoel Becker 
2376427a727SJoel Becker 	kfree(c);
2386427a727SJoel Becker }
2396427a727SJoel Becker 
ocfs2_control_cfu(void * target,size_t target_len,const char __user * buf,size_t count)2403cfd4ab6SJoel Becker static int ocfs2_control_cfu(void *target, size_t target_len,
241462c7e6aSJoel Becker 			     const char __user *buf, size_t count)
242462c7e6aSJoel Becker {
243462c7e6aSJoel Becker 	/* The T01 expects write(2) calls to have exactly one command */
2443cfd4ab6SJoel Becker 	if ((count != target_len) ||
2453cfd4ab6SJoel Becker 	    (count > sizeof(union ocfs2_control_message)))
246462c7e6aSJoel Becker 		return -EINVAL;
247462c7e6aSJoel Becker 
248462c7e6aSJoel Becker 	if (copy_from_user(target, buf, target_len))
249462c7e6aSJoel Becker 		return -EFAULT;
250462c7e6aSJoel Becker 
2513cfd4ab6SJoel Becker 	return 0;
252462c7e6aSJoel Becker }
253462c7e6aSJoel Becker 
ocfs2_control_validate_protocol(struct file * file,const char __user * buf,size_t count)2543cfd4ab6SJoel Becker static ssize_t ocfs2_control_validate_protocol(struct file *file,
255462c7e6aSJoel Becker 					       const char __user *buf,
256462c7e6aSJoel Becker 					       size_t count)
257462c7e6aSJoel Becker {
258462c7e6aSJoel Becker 	ssize_t ret;
259462c7e6aSJoel Becker 	char kbuf[OCFS2_CONTROL_PROTO_LEN];
260462c7e6aSJoel Becker 
261462c7e6aSJoel Becker 	ret = ocfs2_control_cfu(kbuf, OCFS2_CONTROL_PROTO_LEN,
262462c7e6aSJoel Becker 				buf, count);
2633cfd4ab6SJoel Becker 	if (ret)
264462c7e6aSJoel Becker 		return ret;
265462c7e6aSJoel Becker 
266462c7e6aSJoel Becker 	if (strncmp(kbuf, OCFS2_CONTROL_PROTO, OCFS2_CONTROL_PROTO_LEN))
267462c7e6aSJoel Becker 		return -EINVAL;
268462c7e6aSJoel Becker 
269462c7e6aSJoel Becker 	ocfs2_control_set_handshake_state(file,
2703cfd4ab6SJoel Becker 					  OCFS2_CONTROL_HANDSHAKE_PROTOCOL);
271462c7e6aSJoel Becker 
272462c7e6aSJoel Becker 	return count;
273462c7e6aSJoel Becker }
274462c7e6aSJoel Becker 
ocfs2_control_send_down(const char * uuid,int nodenum)275de870ef0SJoel Becker static void ocfs2_control_send_down(const char *uuid,
276de870ef0SJoel Becker 				    int nodenum)
277de870ef0SJoel Becker {
278de870ef0SJoel Becker 	struct ocfs2_live_connection *c;
279de870ef0SJoel Becker 
280de870ef0SJoel Becker 	mutex_lock(&ocfs2_control_lock);
281de870ef0SJoel Becker 
282de870ef0SJoel Becker 	c = ocfs2_connection_find(uuid);
283de870ef0SJoel Becker 	if (c) {
284de870ef0SJoel Becker 		BUG_ON(c->oc_conn == NULL);
285de870ef0SJoel Becker 		c->oc_conn->cc_recovery_handler(nodenum,
286de870ef0SJoel Becker 						c->oc_conn->cc_recovery_data);
287de870ef0SJoel Becker 	}
288de870ef0SJoel Becker 
289de870ef0SJoel Becker 	mutex_unlock(&ocfs2_control_lock);
290de870ef0SJoel Becker }
291de870ef0SJoel Becker 
2923cfd4ab6SJoel Becker /*
2933cfd4ab6SJoel Becker  * Called whenever configuration elements are sent to /dev/ocfs2_control.
2943cfd4ab6SJoel Becker  * If all configuration elements are present, try to set the global
295d4b95eefSJoel Becker  * values.  If there is a problem, return an error.  Skip any missing
296d4b95eefSJoel Becker  * elements, and only bump ocfs2_control_opened when we have all elements
297d4b95eefSJoel Becker  * and are successful.
2983cfd4ab6SJoel Becker  */
ocfs2_control_install_private(struct file * file)2993cfd4ab6SJoel Becker static int ocfs2_control_install_private(struct file *file)
300de870ef0SJoel Becker {
3013cfd4ab6SJoel Becker 	int rc = 0;
3023cfd4ab6SJoel Becker 	int set_p = 1;
3033cfd4ab6SJoel Becker 	struct ocfs2_control_private *p = file->private_data;
3043cfd4ab6SJoel Becker 
3053cfd4ab6SJoel Becker 	BUG_ON(p->op_state != OCFS2_CONTROL_HANDSHAKE_PROTOCOL);
3063cfd4ab6SJoel Becker 
3073cfd4ab6SJoel Becker 	mutex_lock(&ocfs2_control_lock);
308d4b95eefSJoel Becker 
309d4b95eefSJoel Becker 	if (p->op_this_node < 0) {
310d4b95eefSJoel Becker 		set_p = 0;
311d4b95eefSJoel Becker 	} else if ((ocfs2_control_this_node >= 0) &&
312d4b95eefSJoel Becker 		   (ocfs2_control_this_node != p->op_this_node)) {
3133cfd4ab6SJoel Becker 		rc = -EINVAL;
314d4b95eefSJoel Becker 		goto out_unlock;
315d4b95eefSJoel Becker 	}
316d4b95eefSJoel Becker 
317d4b95eefSJoel Becker 	if (!p->op_proto.pv_major) {
318d4b95eefSJoel Becker 		set_p = 0;
319d4b95eefSJoel Becker 	} else if (!list_empty(&ocfs2_live_connection_list) &&
320d4b95eefSJoel Becker 		   ((running_proto.pv_major != p->op_proto.pv_major) ||
321d4b95eefSJoel Becker 		    (running_proto.pv_minor != p->op_proto.pv_minor))) {
322d4b95eefSJoel Becker 		rc = -EINVAL;
323d4b95eefSJoel Becker 		goto out_unlock;
324d4b95eefSJoel Becker 	}
325d4b95eefSJoel Becker 
326d4b95eefSJoel Becker 	if (set_p) {
327d4b95eefSJoel Becker 		ocfs2_control_this_node = p->op_this_node;
328d4b95eefSJoel Becker 		running_proto.pv_major = p->op_proto.pv_major;
329d4b95eefSJoel Becker 		running_proto.pv_minor = p->op_proto.pv_minor;
330d4b95eefSJoel Becker 	}
331d4b95eefSJoel Becker 
332d4b95eefSJoel Becker out_unlock:
3333cfd4ab6SJoel Becker 	mutex_unlock(&ocfs2_control_lock);
3343cfd4ab6SJoel Becker 
3353cfd4ab6SJoel Becker 	if (!rc && set_p) {
3363cfd4ab6SJoel Becker 		/* We set the global values successfully */
3373cfd4ab6SJoel Becker 		atomic_inc(&ocfs2_control_opened);
3383cfd4ab6SJoel Becker 		ocfs2_control_set_handshake_state(file,
3393cfd4ab6SJoel Becker 					OCFS2_CONTROL_HANDSHAKE_VALID);
3403cfd4ab6SJoel Becker 	}
3413cfd4ab6SJoel Becker 
3423cfd4ab6SJoel Becker 	return rc;
3433cfd4ab6SJoel Becker }
3443cfd4ab6SJoel Becker 
ocfs2_control_get_this_node(void)345cf4d8d75SDavid Teigland static int ocfs2_control_get_this_node(void)
346cf4d8d75SDavid Teigland {
347cf4d8d75SDavid Teigland 	int rc;
348cf4d8d75SDavid Teigland 
349cf4d8d75SDavid Teigland 	mutex_lock(&ocfs2_control_lock);
350cf4d8d75SDavid Teigland 	if (ocfs2_control_this_node < 0)
351cf4d8d75SDavid Teigland 		rc = -EINVAL;
352cf4d8d75SDavid Teigland 	else
353cf4d8d75SDavid Teigland 		rc = ocfs2_control_this_node;
354cf4d8d75SDavid Teigland 	mutex_unlock(&ocfs2_control_lock);
355cf4d8d75SDavid Teigland 
356cf4d8d75SDavid Teigland 	return rc;
357cf4d8d75SDavid Teigland }
358cf4d8d75SDavid Teigland 
ocfs2_control_do_setnode_msg(struct file * file,struct ocfs2_control_message_setn * msg)3593cfd4ab6SJoel Becker static int ocfs2_control_do_setnode_msg(struct file *file,
3603cfd4ab6SJoel Becker 					struct ocfs2_control_message_setn *msg)
3613cfd4ab6SJoel Becker {
362de870ef0SJoel Becker 	long nodenum;
3633cfd4ab6SJoel Becker 	char *ptr = NULL;
3643cfd4ab6SJoel Becker 	struct ocfs2_control_private *p = file->private_data;
365de870ef0SJoel Becker 
3663cfd4ab6SJoel Becker 	if (ocfs2_control_get_handshake_state(file) !=
3673cfd4ab6SJoel Becker 	    OCFS2_CONTROL_HANDSHAKE_PROTOCOL)
368de870ef0SJoel Becker 		return -EINVAL;
369de870ef0SJoel Becker 
3703cfd4ab6SJoel Becker 	if (strncmp(msg->tag, OCFS2_CONTROL_MESSAGE_SETNODE_OP,
3713cfd4ab6SJoel Becker 		    OCFS2_CONTROL_MESSAGE_OP_LEN))
372de870ef0SJoel Becker 		return -EINVAL;
373de870ef0SJoel Becker 
3743cfd4ab6SJoel Becker 	if ((msg->space != ' ') || (msg->newline != '\n'))
3753cfd4ab6SJoel Becker 		return -EINVAL;
3763cfd4ab6SJoel Becker 	msg->space = msg->newline = '\0';
3773cfd4ab6SJoel Becker 
3783cfd4ab6SJoel Becker 	nodenum = simple_strtol(msg->nodestr, &ptr, 16);
3793cfd4ab6SJoel Becker 	if (!ptr || *ptr)
3803cfd4ab6SJoel Becker 		return -EINVAL;
3813cfd4ab6SJoel Becker 
3823cfd4ab6SJoel Becker 	if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
3833cfd4ab6SJoel Becker 	    (nodenum > INT_MAX) || (nodenum < 0))
3843cfd4ab6SJoel Becker 		return -ERANGE;
3853cfd4ab6SJoel Becker 	p->op_this_node = nodenum;
3863cfd4ab6SJoel Becker 
3873cfd4ab6SJoel Becker 	return ocfs2_control_install_private(file);
3883cfd4ab6SJoel Becker }
3893cfd4ab6SJoel Becker 
ocfs2_control_do_setversion_msg(struct file * file,struct ocfs2_control_message_setv * msg)390d4b95eefSJoel Becker static int ocfs2_control_do_setversion_msg(struct file *file,
391d4b95eefSJoel Becker 					   struct ocfs2_control_message_setv *msg)
392d4b95eefSJoel Becker {
393d4b95eefSJoel Becker 	long major, minor;
394d4b95eefSJoel Becker 	char *ptr = NULL;
395d4b95eefSJoel Becker 	struct ocfs2_control_private *p = file->private_data;
396d4b95eefSJoel Becker 	struct ocfs2_protocol_version *max =
397e603cfb0SJoel Becker 		&ocfs2_user_plugin.sp_max_proto;
398d4b95eefSJoel Becker 
399d4b95eefSJoel Becker 	if (ocfs2_control_get_handshake_state(file) !=
400d4b95eefSJoel Becker 	    OCFS2_CONTROL_HANDSHAKE_PROTOCOL)
401d4b95eefSJoel Becker 		return -EINVAL;
402d4b95eefSJoel Becker 
403d4b95eefSJoel Becker 	if (strncmp(msg->tag, OCFS2_CONTROL_MESSAGE_SETVERSION_OP,
404d4b95eefSJoel Becker 		    OCFS2_CONTROL_MESSAGE_OP_LEN))
405d4b95eefSJoel Becker 		return -EINVAL;
406d4b95eefSJoel Becker 
407d4b95eefSJoel Becker 	if ((msg->space1 != ' ') || (msg->space2 != ' ') ||
408d4b95eefSJoel Becker 	    (msg->newline != '\n'))
409d4b95eefSJoel Becker 		return -EINVAL;
410d4b95eefSJoel Becker 	msg->space1 = msg->space2 = msg->newline = '\0';
411d4b95eefSJoel Becker 
412d4b95eefSJoel Becker 	major = simple_strtol(msg->major, &ptr, 16);
413d4b95eefSJoel Becker 	if (!ptr || *ptr)
414d4b95eefSJoel Becker 		return -EINVAL;
415d4b95eefSJoel Becker 	minor = simple_strtol(msg->minor, &ptr, 16);
416d4b95eefSJoel Becker 	if (!ptr || *ptr)
417d4b95eefSJoel Becker 		return -EINVAL;
418d4b95eefSJoel Becker 
419d4b95eefSJoel Becker 	/*
420d4b95eefSJoel Becker 	 * The major must be between 1 and 255, inclusive.  The minor
421d4b95eefSJoel Becker 	 * must be between 0 and 255, inclusive.  The version passed in
422d4b95eefSJoel Becker 	 * must be within the maximum version supported by the filesystem.
423d4b95eefSJoel Becker 	 */
424d4b95eefSJoel Becker 	if ((major == LONG_MIN) || (major == LONG_MAX) ||
425d4b95eefSJoel Becker 	    (major > (u8)-1) || (major < 1))
426d4b95eefSJoel Becker 		return -ERANGE;
427d4b95eefSJoel Becker 	if ((minor == LONG_MIN) || (minor == LONG_MAX) ||
428d4b95eefSJoel Becker 	    (minor > (u8)-1) || (minor < 0))
429d4b95eefSJoel Becker 		return -ERANGE;
430d4b95eefSJoel Becker 	if ((major != max->pv_major) ||
431d4b95eefSJoel Becker 	    (minor > max->pv_minor))
432d4b95eefSJoel Becker 		return -EINVAL;
433d4b95eefSJoel Becker 
434d4b95eefSJoel Becker 	p->op_proto.pv_major = major;
435d4b95eefSJoel Becker 	p->op_proto.pv_minor = minor;
436d4b95eefSJoel Becker 
437d4b95eefSJoel Becker 	return ocfs2_control_install_private(file);
438d4b95eefSJoel Becker }
439d4b95eefSJoel Becker 
ocfs2_control_do_down_msg(struct file * file,struct ocfs2_control_message_down * msg)4403cfd4ab6SJoel Becker static int ocfs2_control_do_down_msg(struct file *file,
4413cfd4ab6SJoel Becker 				     struct ocfs2_control_message_down *msg)
4423cfd4ab6SJoel Becker {
4433cfd4ab6SJoel Becker 	long nodenum;
4443cfd4ab6SJoel Becker 	char *p = NULL;
4453cfd4ab6SJoel Becker 
4463cfd4ab6SJoel Becker 	if (ocfs2_control_get_handshake_state(file) !=
4473cfd4ab6SJoel Becker 	    OCFS2_CONTROL_HANDSHAKE_VALID)
4483cfd4ab6SJoel Becker 		return -EINVAL;
4493cfd4ab6SJoel Becker 
4503cfd4ab6SJoel Becker 	if (strncmp(msg->tag, OCFS2_CONTROL_MESSAGE_DOWN_OP,
4513cfd4ab6SJoel Becker 		    OCFS2_CONTROL_MESSAGE_OP_LEN))
4523cfd4ab6SJoel Becker 		return -EINVAL;
4533cfd4ab6SJoel Becker 
4543cfd4ab6SJoel Becker 	if ((msg->space1 != ' ') || (msg->space2 != ' ') ||
4553cfd4ab6SJoel Becker 	    (msg->newline != '\n'))
4563cfd4ab6SJoel Becker 		return -EINVAL;
4573cfd4ab6SJoel Becker 	msg->space1 = msg->space2 = msg->newline = '\0';
4583cfd4ab6SJoel Becker 
4593cfd4ab6SJoel Becker 	nodenum = simple_strtol(msg->nodestr, &p, 16);
460de870ef0SJoel Becker 	if (!p || *p)
461de870ef0SJoel Becker 		return -EINVAL;
462de870ef0SJoel Becker 
463de870ef0SJoel Becker 	if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
464de870ef0SJoel Becker 	    (nodenum > INT_MAX) || (nodenum < 0))
465de870ef0SJoel Becker 		return -ERANGE;
466de870ef0SJoel Becker 
4673cfd4ab6SJoel Becker 	ocfs2_control_send_down(msg->uuid, nodenum);
468de870ef0SJoel Becker 
4693cfd4ab6SJoel Becker 	return 0;
4703cfd4ab6SJoel Becker }
4713cfd4ab6SJoel Becker 
ocfs2_control_message(struct file * file,const char __user * buf,size_t count)4723cfd4ab6SJoel Becker static ssize_t ocfs2_control_message(struct file *file,
4733cfd4ab6SJoel Becker 				     const char __user *buf,
4743cfd4ab6SJoel Becker 				     size_t count)
4753cfd4ab6SJoel Becker {
4763cfd4ab6SJoel Becker 	ssize_t ret;
4773cfd4ab6SJoel Becker 	union ocfs2_control_message msg;
4783cfd4ab6SJoel Becker 
4793cfd4ab6SJoel Becker 	/* Try to catch padding issues */
4803cfd4ab6SJoel Becker 	WARN_ON(offsetof(struct ocfs2_control_message_down, uuid) !=
4813cfd4ab6SJoel Becker 		(sizeof(msg.u_down.tag) + sizeof(msg.u_down.space1)));
4823cfd4ab6SJoel Becker 
4833cfd4ab6SJoel Becker 	memset(&msg, 0, sizeof(union ocfs2_control_message));
4843cfd4ab6SJoel Becker 	ret = ocfs2_control_cfu(&msg, count, buf, count);
4853cfd4ab6SJoel Becker 	if (ret)
4863cfd4ab6SJoel Becker 		goto out;
4873cfd4ab6SJoel Becker 
4883cfd4ab6SJoel Becker 	if ((count == OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN) &&
4893cfd4ab6SJoel Becker 	    !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETNODE_OP,
4903cfd4ab6SJoel Becker 		     OCFS2_CONTROL_MESSAGE_OP_LEN))
4913cfd4ab6SJoel Becker 		ret = ocfs2_control_do_setnode_msg(file, &msg.u_setn);
492d4b95eefSJoel Becker 	else if ((count == OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN) &&
493d4b95eefSJoel Becker 		 !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETVERSION_OP,
494d4b95eefSJoel Becker 			  OCFS2_CONTROL_MESSAGE_OP_LEN))
495d4b95eefSJoel Becker 		ret = ocfs2_control_do_setversion_msg(file, &msg.u_setv);
4963cfd4ab6SJoel Becker 	else if ((count == OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN) &&
4973cfd4ab6SJoel Becker 		 !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_DOWN_OP,
4983cfd4ab6SJoel Becker 			  OCFS2_CONTROL_MESSAGE_OP_LEN))
4993cfd4ab6SJoel Becker 		ret = ocfs2_control_do_down_msg(file, &msg.u_down);
5003cfd4ab6SJoel Becker 	else
5013cfd4ab6SJoel Becker 		ret = -EINVAL;
5023cfd4ab6SJoel Becker 
5033cfd4ab6SJoel Becker out:
5043cfd4ab6SJoel Becker 	return ret ? ret : count;
505de870ef0SJoel Becker }
5066427a727SJoel Becker 
ocfs2_control_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)5076427a727SJoel Becker static ssize_t ocfs2_control_write(struct file *file,
5086427a727SJoel Becker 				   const char __user *buf,
5096427a727SJoel Becker 				   size_t count,
5106427a727SJoel Becker 				   loff_t *ppos)
5118adf0536SJoel Becker {
512462c7e6aSJoel Becker 	ssize_t ret;
513462c7e6aSJoel Becker 
514462c7e6aSJoel Becker 	switch (ocfs2_control_get_handshake_state(file)) {
515462c7e6aSJoel Becker 		case OCFS2_CONTROL_HANDSHAKE_INVALID:
516462c7e6aSJoel Becker 			ret = -EINVAL;
517462c7e6aSJoel Becker 			break;
518462c7e6aSJoel Becker 
519462c7e6aSJoel Becker 		case OCFS2_CONTROL_HANDSHAKE_READ:
5203cfd4ab6SJoel Becker 			ret = ocfs2_control_validate_protocol(file, buf,
521462c7e6aSJoel Becker 							      count);
522462c7e6aSJoel Becker 			break;
523462c7e6aSJoel Becker 
5243cfd4ab6SJoel Becker 		case OCFS2_CONTROL_HANDSHAKE_PROTOCOL:
525462c7e6aSJoel Becker 		case OCFS2_CONTROL_HANDSHAKE_VALID:
526de870ef0SJoel Becker 			ret = ocfs2_control_message(file, buf, count);
527462c7e6aSJoel Becker 			break;
528462c7e6aSJoel Becker 
529462c7e6aSJoel Becker 		default:
530462c7e6aSJoel Becker 			BUG();
531462c7e6aSJoel Becker 			ret = -EIO;
532462c7e6aSJoel Becker 			break;
5338adf0536SJoel Becker 	}
5348adf0536SJoel Becker 
535462c7e6aSJoel Becker 	return ret;
536462c7e6aSJoel Becker }
537462c7e6aSJoel Becker 
538462c7e6aSJoel Becker /*
539462c7e6aSJoel Becker  * This is a naive version.  If we ever have a new protocol, we'll expand
540462c7e6aSJoel Becker  * it.  Probably using seq_file.
541462c7e6aSJoel Becker  */
ocfs2_control_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)5426427a727SJoel Becker static ssize_t ocfs2_control_read(struct file *file,
5436427a727SJoel Becker 				  char __user *buf,
5446427a727SJoel Becker 				  size_t count,
5456427a727SJoel Becker 				  loff_t *ppos)
5466427a727SJoel Becker {
5477600c72bSAkinobu Mita 	ssize_t ret;
548462c7e6aSJoel Becker 
5497600c72bSAkinobu Mita 	ret = simple_read_from_buffer(buf, count, ppos,
5507600c72bSAkinobu Mita 			OCFS2_CONTROL_PROTO, OCFS2_CONTROL_PROTO_LEN);
551462c7e6aSJoel Becker 
552462c7e6aSJoel Becker 	/* Have we read the whole protocol list? */
5537600c72bSAkinobu Mita 	if (ret > 0 && *ppos >= OCFS2_CONTROL_PROTO_LEN)
554462c7e6aSJoel Becker 		ocfs2_control_set_handshake_state(file,
555462c7e6aSJoel Becker 						  OCFS2_CONTROL_HANDSHAKE_READ);
556462c7e6aSJoel Becker 
5577600c72bSAkinobu Mita 	return ret;
5586427a727SJoel Becker }
5596427a727SJoel Becker 
ocfs2_control_release(struct inode * inode,struct file * file)5606427a727SJoel Becker static int ocfs2_control_release(struct inode *inode, struct file *file)
5616427a727SJoel Becker {
562462c7e6aSJoel Becker 	struct ocfs2_control_private *p = file->private_data;
563462c7e6aSJoel Becker 
5646427a727SJoel Becker 	mutex_lock(&ocfs2_control_lock);
565462c7e6aSJoel Becker 
566462c7e6aSJoel Becker 	if (ocfs2_control_get_handshake_state(file) !=
567462c7e6aSJoel Becker 	    OCFS2_CONTROL_HANDSHAKE_VALID)
568462c7e6aSJoel Becker 		goto out;
569462c7e6aSJoel Becker 
570462c7e6aSJoel Becker 	if (atomic_dec_and_test(&ocfs2_control_opened)) {
5716427a727SJoel Becker 		if (!list_empty(&ocfs2_live_connection_list)) {
5726427a727SJoel Becker 			/* XXX: Do bad things! */
5736427a727SJoel Becker 			printk(KERN_ERR
5746427a727SJoel Becker 			       "ocfs2: Unexpected release of ocfs2_control!\n"
5756427a727SJoel Becker 			       "       Loss of cluster connection requires "
5766427a727SJoel Becker 			       "an emergency restart!\n");
5776427a727SJoel Becker 			emergency_restart();
5786427a727SJoel Becker 		}
579d4b95eefSJoel Becker 		/*
580d4b95eefSJoel Becker 		 * Last valid close clears the node number and resets
581d4b95eefSJoel Becker 		 * the locking protocol version
582d4b95eefSJoel Becker 		 */
5833cfd4ab6SJoel Becker 		ocfs2_control_this_node = -1;
584d4b95eefSJoel Becker 		running_proto.pv_major = 0;
58598acbf63SAndrew Morton 		running_proto.pv_minor = 0;
5866427a727SJoel Becker 	}
5876427a727SJoel Becker 
588462c7e6aSJoel Becker out:
589462c7e6aSJoel Becker 	list_del_init(&p->op_list);
590462c7e6aSJoel Becker 	file->private_data = NULL;
591462c7e6aSJoel Becker 
592462c7e6aSJoel Becker 	mutex_unlock(&ocfs2_control_lock);
593462c7e6aSJoel Becker 
594462c7e6aSJoel Becker 	kfree(p);
595462c7e6aSJoel Becker 
5966427a727SJoel Becker 	return 0;
5976427a727SJoel Becker }
5986427a727SJoel Becker 
ocfs2_control_open(struct inode * inode,struct file * file)5996427a727SJoel Becker static int ocfs2_control_open(struct inode *inode, struct file *file)
6006427a727SJoel Becker {
601462c7e6aSJoel Becker 	struct ocfs2_control_private *p;
602462c7e6aSJoel Becker 
603462c7e6aSJoel Becker 	p = kzalloc(sizeof(struct ocfs2_control_private), GFP_KERNEL);
604462c7e6aSJoel Becker 	if (!p)
605462c7e6aSJoel Becker 		return -ENOMEM;
6063cfd4ab6SJoel Becker 	p->op_this_node = -1;
607462c7e6aSJoel Becker 
608462c7e6aSJoel Becker 	mutex_lock(&ocfs2_control_lock);
609462c7e6aSJoel Becker 	file->private_data = p;
610462c7e6aSJoel Becker 	list_add(&p->op_list, &ocfs2_control_private_list);
611462c7e6aSJoel Becker 	mutex_unlock(&ocfs2_control_lock);
6126427a727SJoel Becker 
6136427a727SJoel Becker 	return 0;
6146427a727SJoel Becker }
6156427a727SJoel Becker 
6166427a727SJoel Becker static const struct file_operations ocfs2_control_fops = {
6176427a727SJoel Becker 	.open    = ocfs2_control_open,
6186427a727SJoel Becker 	.release = ocfs2_control_release,
6196427a727SJoel Becker 	.read    = ocfs2_control_read,
6206427a727SJoel Becker 	.write   = ocfs2_control_write,
6216427a727SJoel Becker 	.owner   = THIS_MODULE,
6226038f373SArnd Bergmann 	.llseek  = default_llseek,
6236427a727SJoel Becker };
6246427a727SJoel Becker 
6254d8755b5SAdrian Bunk static struct miscdevice ocfs2_control_device = {
6266427a727SJoel Becker 	.minor		= MISC_DYNAMIC_MINOR,
6276427a727SJoel Becker 	.name		= "ocfs2_control",
6286427a727SJoel Becker 	.fops		= &ocfs2_control_fops,
6296427a727SJoel Becker };
6306427a727SJoel Becker 
ocfs2_control_init(void)6316427a727SJoel Becker static int ocfs2_control_init(void)
6326427a727SJoel Becker {
6336427a727SJoel Becker 	int rc;
6346427a727SJoel Becker 
6356427a727SJoel Becker 	atomic_set(&ocfs2_control_opened, 0);
6366427a727SJoel Becker 
6376427a727SJoel Becker 	rc = misc_register(&ocfs2_control_device);
6386427a727SJoel Becker 	if (rc)
6396427a727SJoel Becker 		printk(KERN_ERR
6406427a727SJoel Becker 		       "ocfs2: Unable to register ocfs2_control device "
6416427a727SJoel Becker 		       "(errno %d)\n",
6426427a727SJoel Becker 		       -rc);
6436427a727SJoel Becker 
6446427a727SJoel Becker 	return rc;
6456427a727SJoel Becker }
6466427a727SJoel Becker 
ocfs2_control_exit(void)6476427a727SJoel Becker static void ocfs2_control_exit(void)
6486427a727SJoel Becker {
649f368ed60SGreg Kroah-Hartman 	misc_deregister(&ocfs2_control_device);
6506427a727SJoel Becker }
6516427a727SJoel Becker 
fsdlm_lock_ast_wrapper(void * astarg)652cf4d8d75SDavid Teigland static void fsdlm_lock_ast_wrapper(void *astarg)
653cf4d8d75SDavid Teigland {
654c0e41338SJoel Becker 	struct ocfs2_dlm_lksb *lksb = astarg;
655a796d286SJoel Becker 	int status = lksb->lksb_fsdlm.sb_status;
656cf4d8d75SDavid Teigland 
657cf4d8d75SDavid Teigland 	/*
658cf4d8d75SDavid Teigland 	 * For now we're punting on the issue of other non-standard errors
659cf4d8d75SDavid Teigland 	 * where we can't tell if the unlock_ast or lock_ast should be called.
660cf4d8d75SDavid Teigland 	 * The main "other error" that's possible is EINVAL which means the
661cf4d8d75SDavid Teigland 	 * function was called with invalid args, which shouldn't be possible
662cf4d8d75SDavid Teigland 	 * since the caller here is under our control.  Other non-standard
663cf4d8d75SDavid Teigland 	 * errors probably fall into the same category, or otherwise are fatal
664cf4d8d75SDavid Teigland 	 * which means we can't carry on anyway.
665cf4d8d75SDavid Teigland 	 */
666cf4d8d75SDavid Teigland 
667cf4d8d75SDavid Teigland 	if (status == -DLM_EUNLOCK || status == -DLM_ECANCEL)
668110946c8SJoel Becker 		lksb->lksb_conn->cc_proto->lp_unlock_ast(lksb, 0);
669cf4d8d75SDavid Teigland 	else
670110946c8SJoel Becker 		lksb->lksb_conn->cc_proto->lp_lock_ast(lksb);
671cf4d8d75SDavid Teigland }
672cf4d8d75SDavid Teigland 
fsdlm_blocking_ast_wrapper(void * astarg,int level)673cf4d8d75SDavid Teigland static void fsdlm_blocking_ast_wrapper(void *astarg, int level)
674cf4d8d75SDavid Teigland {
675c0e41338SJoel Becker 	struct ocfs2_dlm_lksb *lksb = astarg;
676a796d286SJoel Becker 
677110946c8SJoel Becker 	lksb->lksb_conn->cc_proto->lp_blocking_ast(lksb, level);
678cf4d8d75SDavid Teigland }
679cf4d8d75SDavid Teigland 
user_dlm_lock(struct ocfs2_cluster_connection * conn,int mode,struct ocfs2_dlm_lksb * lksb,u32 flags,void * name,unsigned int namelen)680cf4d8d75SDavid Teigland static int user_dlm_lock(struct ocfs2_cluster_connection *conn,
681cf4d8d75SDavid Teigland 			 int mode,
682c0e41338SJoel Becker 			 struct ocfs2_dlm_lksb *lksb,
683cf4d8d75SDavid Teigland 			 u32 flags,
684cf4d8d75SDavid Teigland 			 void *name,
685a796d286SJoel Becker 			 unsigned int namelen)
686cf4d8d75SDavid Teigland {
687cf4d8d75SDavid Teigland 	if (!lksb->lksb_fsdlm.sb_lvbptr)
688cf4d8d75SDavid Teigland 		lksb->lksb_fsdlm.sb_lvbptr = (char *)lksb +
689cf4d8d75SDavid Teigland 					     sizeof(struct dlm_lksb);
690cf4d8d75SDavid Teigland 
69138c9d2d3SJoseph Qi 	return dlm_lock(conn->cc_lockspace, mode, &lksb->lksb_fsdlm,
692cf4d8d75SDavid Teigland 			flags|DLM_LKF_NODLCKWT, name, namelen, 0,
693a796d286SJoel Becker 			fsdlm_lock_ast_wrapper, lksb,
694cf4d8d75SDavid Teigland 			fsdlm_blocking_ast_wrapper);
695cf4d8d75SDavid Teigland }
696cf4d8d75SDavid Teigland 
user_dlm_unlock(struct ocfs2_cluster_connection * conn,struct ocfs2_dlm_lksb * lksb,u32 flags)697cf4d8d75SDavid Teigland static int user_dlm_unlock(struct ocfs2_cluster_connection *conn,
698c0e41338SJoel Becker 			   struct ocfs2_dlm_lksb *lksb,
699a796d286SJoel Becker 			   u32 flags)
700cf4d8d75SDavid Teigland {
70138c9d2d3SJoseph Qi 	return dlm_unlock(conn->cc_lockspace, lksb->lksb_fsdlm.sb_lkid,
702a796d286SJoel Becker 			  flags, &lksb->lksb_fsdlm, lksb);
703cf4d8d75SDavid Teigland }
704cf4d8d75SDavid Teigland 
user_dlm_lock_status(struct ocfs2_dlm_lksb * lksb)705c0e41338SJoel Becker static int user_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
706cf4d8d75SDavid Teigland {
707cf4d8d75SDavid Teigland 	return lksb->lksb_fsdlm.sb_status;
708cf4d8d75SDavid Teigland }
709cf4d8d75SDavid Teigland 
user_dlm_lvb_valid(struct ocfs2_dlm_lksb * lksb)710c0e41338SJoel Becker static int user_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
7111c520dfbSJoel Becker {
7121c520dfbSJoel Becker 	int invalid = lksb->lksb_fsdlm.sb_flags & DLM_SBF_VALNOTVALID;
7131c520dfbSJoel Becker 
7141c520dfbSJoel Becker 	return !invalid;
7151c520dfbSJoel Becker }
7161c520dfbSJoel Becker 
user_dlm_lvb(struct ocfs2_dlm_lksb * lksb)717c0e41338SJoel Becker static void *user_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
718cf4d8d75SDavid Teigland {
71966f502a4SDavid Teigland 	if (!lksb->lksb_fsdlm.sb_lvbptr)
72066f502a4SDavid Teigland 		lksb->lksb_fsdlm.sb_lvbptr = (char *)lksb +
72166f502a4SDavid Teigland 					     sizeof(struct dlm_lksb);
722cf4d8d75SDavid Teigland 	return (void *)(lksb->lksb_fsdlm.sb_lvbptr);
723cf4d8d75SDavid Teigland }
724cf4d8d75SDavid Teigland 
user_dlm_dump_lksb(struct ocfs2_dlm_lksb * lksb)725c0e41338SJoel Becker static void user_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb)
726cf4d8d75SDavid Teigland {
727cf4d8d75SDavid Teigland }
728cf4d8d75SDavid Teigland 
user_plock(struct ocfs2_cluster_connection * conn,u64 ino,struct file * file,int cmd,struct file_lock * fl)72953da4939SMark Fasheh static int user_plock(struct ocfs2_cluster_connection *conn,
73053da4939SMark Fasheh 		      u64 ino,
73153da4939SMark Fasheh 		      struct file *file,
73253da4939SMark Fasheh 		      int cmd,
73353da4939SMark Fasheh 		      struct file_lock *fl)
73453da4939SMark Fasheh {
73553da4939SMark Fasheh 	/*
73653da4939SMark Fasheh 	 * This more or less just demuxes the plock request into any
73753da4939SMark Fasheh 	 * one of three dlm calls.
73853da4939SMark Fasheh 	 *
73953da4939SMark Fasheh 	 * Internally, fs/dlm will pass these to a misc device, which
74053da4939SMark Fasheh 	 * a userspace daemon will read and write to.
74153da4939SMark Fasheh 	 */
74253da4939SMark Fasheh 
743*dc52cd2eSAlexander Aring 	if (cmd == F_CANCELLK)
744*dc52cd2eSAlexander Aring 		return dlm_posix_cancel(conn->cc_lockspace, ino, file, fl);
745*dc52cd2eSAlexander Aring 	else if (IS_GETLK(cmd))
74653da4939SMark Fasheh 		return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
74753da4939SMark Fasheh 	else if (fl->fl_type == F_UNLCK)
74853da4939SMark Fasheh 		return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);
74953da4939SMark Fasheh 	else
75053da4939SMark Fasheh 		return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl);
75153da4939SMark Fasheh }
75253da4939SMark Fasheh 
753cf4d8d75SDavid Teigland /*
754cf4d8d75SDavid Teigland  * Compare a requested locking protocol version against the current one.
755cf4d8d75SDavid Teigland  *
756cf4d8d75SDavid Teigland  * If the major numbers are different, they are incompatible.
757cf4d8d75SDavid Teigland  * If the current minor is greater than the request, they are incompatible.
758cf4d8d75SDavid Teigland  * If the current minor is less than or equal to the request, they are
759cf4d8d75SDavid Teigland  * compatible, and the requester should run at the current minor version.
760cf4d8d75SDavid Teigland  */
fs_protocol_compare(struct ocfs2_protocol_version * existing,struct ocfs2_protocol_version * request)761cf4d8d75SDavid Teigland static int fs_protocol_compare(struct ocfs2_protocol_version *existing,
762cf4d8d75SDavid Teigland 			       struct ocfs2_protocol_version *request)
763cf4d8d75SDavid Teigland {
764cf4d8d75SDavid Teigland 	if (existing->pv_major != request->pv_major)
765cf4d8d75SDavid Teigland 		return 1;
766cf4d8d75SDavid Teigland 
767cf4d8d75SDavid Teigland 	if (existing->pv_minor > request->pv_minor)
768cf4d8d75SDavid Teigland 		return 1;
769cf4d8d75SDavid Teigland 
770cf4d8d75SDavid Teigland 	if (existing->pv_minor < request->pv_minor)
771cf4d8d75SDavid Teigland 		request->pv_minor = existing->pv_minor;
772cf4d8d75SDavid Teigland 
773cf4d8d75SDavid Teigland 	return 0;
774cf4d8d75SDavid Teigland }
775cf4d8d75SDavid Teigland 
lvb_to_version(char * lvb,struct ocfs2_protocol_version * ver)77641503630SGoldwyn Rodrigues static void lvb_to_version(char *lvb, struct ocfs2_protocol_version *ver)
77741503630SGoldwyn Rodrigues {
77841503630SGoldwyn Rodrigues 	struct ocfs2_protocol_version *pv =
77941503630SGoldwyn Rodrigues 		(struct ocfs2_protocol_version *)lvb;
78041503630SGoldwyn Rodrigues 	/*
78141503630SGoldwyn Rodrigues 	 * ocfs2_protocol_version has two u8 variables, so we don't
78241503630SGoldwyn Rodrigues 	 * need any endian conversion.
78341503630SGoldwyn Rodrigues 	 */
78441503630SGoldwyn Rodrigues 	ver->pv_major = pv->pv_major;
78541503630SGoldwyn Rodrigues 	ver->pv_minor = pv->pv_minor;
78641503630SGoldwyn Rodrigues }
78741503630SGoldwyn Rodrigues 
version_to_lvb(struct ocfs2_protocol_version * ver,char * lvb)78841503630SGoldwyn Rodrigues static void version_to_lvb(struct ocfs2_protocol_version *ver, char *lvb)
78941503630SGoldwyn Rodrigues {
79041503630SGoldwyn Rodrigues 	struct ocfs2_protocol_version *pv =
79141503630SGoldwyn Rodrigues 		(struct ocfs2_protocol_version *)lvb;
79241503630SGoldwyn Rodrigues 	/*
79341503630SGoldwyn Rodrigues 	 * ocfs2_protocol_version has two u8 variables, so we don't
79441503630SGoldwyn Rodrigues 	 * need any endian conversion.
79541503630SGoldwyn Rodrigues 	 */
79641503630SGoldwyn Rodrigues 	pv->pv_major = ver->pv_major;
79741503630SGoldwyn Rodrigues 	pv->pv_minor = ver->pv_minor;
79841503630SGoldwyn Rodrigues }
79941503630SGoldwyn Rodrigues 
sync_wait_cb(void * arg)80041503630SGoldwyn Rodrigues static void sync_wait_cb(void *arg)
80141503630SGoldwyn Rodrigues {
80241503630SGoldwyn Rodrigues 	struct ocfs2_cluster_connection *conn = arg;
80341503630SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
80441503630SGoldwyn Rodrigues 	complete(&lc->oc_sync_wait);
80541503630SGoldwyn Rodrigues }
80641503630SGoldwyn Rodrigues 
sync_unlock(struct ocfs2_cluster_connection * conn,struct dlm_lksb * lksb,char * name)80741503630SGoldwyn Rodrigues static int sync_unlock(struct ocfs2_cluster_connection *conn,
80841503630SGoldwyn Rodrigues 		struct dlm_lksb *lksb, char *name)
80941503630SGoldwyn Rodrigues {
81041503630SGoldwyn Rodrigues 	int error;
81141503630SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
81241503630SGoldwyn Rodrigues 
81341503630SGoldwyn Rodrigues 	error = dlm_unlock(conn->cc_lockspace, lksb->sb_lkid, 0, lksb, conn);
81441503630SGoldwyn Rodrigues 	if (error) {
81541503630SGoldwyn Rodrigues 		printk(KERN_ERR "%s lkid %x error %d\n",
81641503630SGoldwyn Rodrigues 				name, lksb->sb_lkid, error);
81741503630SGoldwyn Rodrigues 		return error;
81841503630SGoldwyn Rodrigues 	}
81941503630SGoldwyn Rodrigues 
82041503630SGoldwyn Rodrigues 	wait_for_completion(&lc->oc_sync_wait);
82141503630SGoldwyn Rodrigues 
82241503630SGoldwyn Rodrigues 	if (lksb->sb_status != -DLM_EUNLOCK) {
82341503630SGoldwyn Rodrigues 		printk(KERN_ERR "%s lkid %x status %d\n",
82441503630SGoldwyn Rodrigues 				name, lksb->sb_lkid, lksb->sb_status);
82541503630SGoldwyn Rodrigues 		return -1;
82641503630SGoldwyn Rodrigues 	}
82741503630SGoldwyn Rodrigues 	return 0;
82841503630SGoldwyn Rodrigues }
82941503630SGoldwyn Rodrigues 
sync_lock(struct ocfs2_cluster_connection * conn,int mode,uint32_t flags,struct dlm_lksb * lksb,char * name)83041503630SGoldwyn Rodrigues static int sync_lock(struct ocfs2_cluster_connection *conn,
83141503630SGoldwyn Rodrigues 		int mode, uint32_t flags,
83241503630SGoldwyn Rodrigues 		struct dlm_lksb *lksb, char *name)
83341503630SGoldwyn Rodrigues {
83441503630SGoldwyn Rodrigues 	int error, status;
83541503630SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
83641503630SGoldwyn Rodrigues 
83741503630SGoldwyn Rodrigues 	error = dlm_lock(conn->cc_lockspace, mode, lksb, flags,
83841503630SGoldwyn Rodrigues 			name, strlen(name),
83941503630SGoldwyn Rodrigues 			0, sync_wait_cb, conn, NULL);
84041503630SGoldwyn Rodrigues 	if (error) {
84141503630SGoldwyn Rodrigues 		printk(KERN_ERR "%s lkid %x flags %x mode %d error %d\n",
84241503630SGoldwyn Rodrigues 				name, lksb->sb_lkid, flags, mode, error);
84341503630SGoldwyn Rodrigues 		return error;
84441503630SGoldwyn Rodrigues 	}
84541503630SGoldwyn Rodrigues 
84641503630SGoldwyn Rodrigues 	wait_for_completion(&lc->oc_sync_wait);
84741503630SGoldwyn Rodrigues 
84841503630SGoldwyn Rodrigues 	status = lksb->sb_status;
84941503630SGoldwyn Rodrigues 
85041503630SGoldwyn Rodrigues 	if (status && status != -EAGAIN) {
85141503630SGoldwyn Rodrigues 		printk(KERN_ERR "%s lkid %x flags %x mode %d status %d\n",
85241503630SGoldwyn Rodrigues 				name, lksb->sb_lkid, flags, mode, status);
85341503630SGoldwyn Rodrigues 	}
85441503630SGoldwyn Rodrigues 
85541503630SGoldwyn Rodrigues 	return status;
85641503630SGoldwyn Rodrigues }
85741503630SGoldwyn Rodrigues 
85841503630SGoldwyn Rodrigues 
version_lock(struct ocfs2_cluster_connection * conn,int mode,int flags)85941503630SGoldwyn Rodrigues static int version_lock(struct ocfs2_cluster_connection *conn, int mode,
86041503630SGoldwyn Rodrigues 		int flags)
86141503630SGoldwyn Rodrigues {
86241503630SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
86341503630SGoldwyn Rodrigues 	return sync_lock(conn, mode, flags,
86441503630SGoldwyn Rodrigues 			&lc->oc_version_lksb, VERSION_LOCK);
86541503630SGoldwyn Rodrigues }
86641503630SGoldwyn Rodrigues 
version_unlock(struct ocfs2_cluster_connection * conn)86741503630SGoldwyn Rodrigues static int version_unlock(struct ocfs2_cluster_connection *conn)
86841503630SGoldwyn Rodrigues {
86941503630SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
87041503630SGoldwyn Rodrigues 	return sync_unlock(conn, &lc->oc_version_lksb, VERSION_LOCK);
87141503630SGoldwyn Rodrigues }
87241503630SGoldwyn Rodrigues 
873c994c2ebSGoldwyn Rodrigues /* get_protocol_version()
874c994c2ebSGoldwyn Rodrigues  *
875c994c2ebSGoldwyn Rodrigues  * To exchange ocfs2 versioning, we use the LVB of the version dlm lock.
876c994c2ebSGoldwyn Rodrigues  * The algorithm is:
877c994c2ebSGoldwyn Rodrigues  * 1. Attempt to take the lock in EX mode (non-blocking).
878c994c2ebSGoldwyn Rodrigues  * 2. If successful (which means it is the first mount), write the
879c994c2ebSGoldwyn Rodrigues  *    version number and downconvert to PR lock.
880c994c2ebSGoldwyn Rodrigues  * 3. If unsuccessful (returns -EAGAIN), read the version from the LVB after
881c994c2ebSGoldwyn Rodrigues  *    taking the PR lock.
882c994c2ebSGoldwyn Rodrigues  */
883c994c2ebSGoldwyn Rodrigues 
get_protocol_version(struct ocfs2_cluster_connection * conn)884c994c2ebSGoldwyn Rodrigues static int get_protocol_version(struct ocfs2_cluster_connection *conn)
885c994c2ebSGoldwyn Rodrigues {
886c994c2ebSGoldwyn Rodrigues 	int ret;
887c994c2ebSGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
888c994c2ebSGoldwyn Rodrigues 	struct ocfs2_protocol_version pv;
889c994c2ebSGoldwyn Rodrigues 
890c994c2ebSGoldwyn Rodrigues 	running_proto.pv_major =
891c994c2ebSGoldwyn Rodrigues 		ocfs2_user_plugin.sp_max_proto.pv_major;
892c994c2ebSGoldwyn Rodrigues 	running_proto.pv_minor =
893c994c2ebSGoldwyn Rodrigues 		ocfs2_user_plugin.sp_max_proto.pv_minor;
894c994c2ebSGoldwyn Rodrigues 
895c994c2ebSGoldwyn Rodrigues 	lc->oc_version_lksb.sb_lvbptr = lc->oc_lvb;
896c994c2ebSGoldwyn Rodrigues 	ret = version_lock(conn, DLM_LOCK_EX,
897c994c2ebSGoldwyn Rodrigues 			DLM_LKF_VALBLK|DLM_LKF_NOQUEUE);
898c994c2ebSGoldwyn Rodrigues 	if (!ret) {
899c994c2ebSGoldwyn Rodrigues 		conn->cc_version.pv_major = running_proto.pv_major;
900c994c2ebSGoldwyn Rodrigues 		conn->cc_version.pv_minor = running_proto.pv_minor;
901c994c2ebSGoldwyn Rodrigues 		version_to_lvb(&running_proto, lc->oc_lvb);
902c994c2ebSGoldwyn Rodrigues 		version_lock(conn, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
903c994c2ebSGoldwyn Rodrigues 	} else if (ret == -EAGAIN) {
904c994c2ebSGoldwyn Rodrigues 		ret = version_lock(conn, DLM_LOCK_PR, DLM_LKF_VALBLK);
905c994c2ebSGoldwyn Rodrigues 		if (ret)
906c994c2ebSGoldwyn Rodrigues 			goto out;
907c994c2ebSGoldwyn Rodrigues 		lvb_to_version(lc->oc_lvb, &pv);
908c994c2ebSGoldwyn Rodrigues 
909c994c2ebSGoldwyn Rodrigues 		if ((pv.pv_major != running_proto.pv_major) ||
910c994c2ebSGoldwyn Rodrigues 				(pv.pv_minor > running_proto.pv_minor)) {
911c994c2ebSGoldwyn Rodrigues 			ret = -EINVAL;
912c994c2ebSGoldwyn Rodrigues 			goto out;
913c994c2ebSGoldwyn Rodrigues 		}
914c994c2ebSGoldwyn Rodrigues 
915c994c2ebSGoldwyn Rodrigues 		conn->cc_version.pv_major = pv.pv_major;
916c994c2ebSGoldwyn Rodrigues 		conn->cc_version.pv_minor = pv.pv_minor;
917c994c2ebSGoldwyn Rodrigues 	}
918c994c2ebSGoldwyn Rodrigues out:
919c994c2ebSGoldwyn Rodrigues 	return ret;
920c994c2ebSGoldwyn Rodrigues }
921c994c2ebSGoldwyn Rodrigues 
user_recover_prep(void * arg)92266e188fcSGoldwyn Rodrigues static void user_recover_prep(void *arg)
92366e188fcSGoldwyn Rodrigues {
92466e188fcSGoldwyn Rodrigues }
92566e188fcSGoldwyn Rodrigues 
user_recover_slot(void * arg,struct dlm_slot * slot)92666e188fcSGoldwyn Rodrigues static void user_recover_slot(void *arg, struct dlm_slot *slot)
92766e188fcSGoldwyn Rodrigues {
92866e188fcSGoldwyn Rodrigues 	struct ocfs2_cluster_connection *conn = arg;
92966e188fcSGoldwyn Rodrigues 	printk(KERN_INFO "ocfs2: Node %d/%d down. Initiating recovery.\n",
93066e188fcSGoldwyn Rodrigues 			slot->nodeid, slot->slot);
93166e188fcSGoldwyn Rodrigues 	conn->cc_recovery_handler(slot->nodeid, conn->cc_recovery_data);
93266e188fcSGoldwyn Rodrigues 
93366e188fcSGoldwyn Rodrigues }
93466e188fcSGoldwyn Rodrigues 
user_recover_done(void * arg,struct dlm_slot * slots,int num_slots,int our_slot,uint32_t generation)93566e188fcSGoldwyn Rodrigues static void user_recover_done(void *arg, struct dlm_slot *slots,
93666e188fcSGoldwyn Rodrigues 		int num_slots, int our_slot,
93766e188fcSGoldwyn Rodrigues 		uint32_t generation)
93866e188fcSGoldwyn Rodrigues {
93966e188fcSGoldwyn Rodrigues 	struct ocfs2_cluster_connection *conn = arg;
94066e188fcSGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
94166e188fcSGoldwyn Rodrigues 	int i;
94266e188fcSGoldwyn Rodrigues 
94366e188fcSGoldwyn Rodrigues 	for (i = 0; i < num_slots; i++)
94466e188fcSGoldwyn Rodrigues 		if (slots[i].slot == our_slot) {
94566e188fcSGoldwyn Rodrigues 			atomic_set(&lc->oc_this_node, slots[i].nodeid);
94666e188fcSGoldwyn Rodrigues 			break;
94766e188fcSGoldwyn Rodrigues 		}
94866e188fcSGoldwyn Rodrigues 
94966e188fcSGoldwyn Rodrigues 	lc->oc_our_slot = our_slot;
950c994c2ebSGoldwyn Rodrigues 	wake_up(&lc->oc_wait);
95166e188fcSGoldwyn Rodrigues }
95266e188fcSGoldwyn Rodrigues 
95316eac4beSWei Yongjun static const struct dlm_lockspace_ops ocfs2_ls_ops = {
95466e188fcSGoldwyn Rodrigues 	.recover_prep = user_recover_prep,
95566e188fcSGoldwyn Rodrigues 	.recover_slot = user_recover_slot,
95666e188fcSGoldwyn Rodrigues 	.recover_done = user_recover_done,
95766e188fcSGoldwyn Rodrigues };
95866e188fcSGoldwyn Rodrigues 
user_cluster_disconnect(struct ocfs2_cluster_connection * conn)959c994c2ebSGoldwyn Rodrigues static int user_cluster_disconnect(struct ocfs2_cluster_connection *conn)
960c994c2ebSGoldwyn Rodrigues {
961c994c2ebSGoldwyn Rodrigues 	version_unlock(conn);
962c994c2ebSGoldwyn Rodrigues 	dlm_release_lockspace(conn->cc_lockspace, 2);
963c994c2ebSGoldwyn Rodrigues 	conn->cc_lockspace = NULL;
964c994c2ebSGoldwyn Rodrigues 	ocfs2_live_connection_drop(conn->cc_private);
965c994c2ebSGoldwyn Rodrigues 	conn->cc_private = NULL;
966c994c2ebSGoldwyn Rodrigues 	return 0;
967c994c2ebSGoldwyn Rodrigues }
968c994c2ebSGoldwyn Rodrigues 
user_cluster_connect(struct ocfs2_cluster_connection * conn)969cf4d8d75SDavid Teigland static int user_cluster_connect(struct ocfs2_cluster_connection *conn)
970cf4d8d75SDavid Teigland {
971cf4d8d75SDavid Teigland 	dlm_lockspace_t *fsdlm;
97224aa3386SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc;
973c994c2ebSGoldwyn Rodrigues 	int rc, ops_rv;
974cf4d8d75SDavid Teigland 
975cf4d8d75SDavid Teigland 	BUG_ON(conn == NULL);
976cf4d8d75SDavid Teigland 
97724aa3386SGoldwyn Rodrigues 	lc = kzalloc(sizeof(struct ocfs2_live_connection), GFP_KERNEL);
97843ee9cadSMarkus Elfring 	if (!lc)
97943ee9cadSMarkus Elfring 		return -ENOMEM;
98024aa3386SGoldwyn Rodrigues 
981c994c2ebSGoldwyn Rodrigues 	init_waitqueue_head(&lc->oc_wait);
982c994c2ebSGoldwyn Rodrigues 	init_completion(&lc->oc_sync_wait);
983c994c2ebSGoldwyn Rodrigues 	atomic_set(&lc->oc_this_node, 0);
984c994c2ebSGoldwyn Rodrigues 	conn->cc_private = lc;
985c994c2ebSGoldwyn Rodrigues 	lc->oc_type = NO_CONTROLD;
986c994c2ebSGoldwyn Rodrigues 
987c994c2ebSGoldwyn Rodrigues 	rc = dlm_new_lockspace(conn->cc_name, conn->cc_cluster_name,
98812cda13cSAlexander Aring 			       DLM_LSFL_NEWEXCL, DLM_LVB_LEN,
989c994c2ebSGoldwyn Rodrigues 			       &ocfs2_ls_ops, conn, &ops_rv, &fsdlm);
99001a36b67SGang He 	if (rc) {
99101a36b67SGang He 		if (rc == -EEXIST || rc == -EPROTO)
99201a36b67SGang He 			printk(KERN_ERR "ocfs2: Unable to create the "
99301a36b67SGang He 				"lockspace %s (%d), because a ocfs2-tools "
99401a36b67SGang He 				"program is running on this file system "
99501a36b67SGang He 				"with the same name lockspace\n",
99601a36b67SGang He 				conn->cc_name, rc);
997c994c2ebSGoldwyn Rodrigues 		goto out;
99801a36b67SGang He 	}
999c994c2ebSGoldwyn Rodrigues 
1000c994c2ebSGoldwyn Rodrigues 	if (ops_rv == -EOPNOTSUPP) {
10013e834151SGoldwyn Rodrigues 		lc->oc_type = WITH_CONTROLD;
1002c994c2ebSGoldwyn Rodrigues 		printk(KERN_NOTICE "ocfs2: You seem to be using an older "
1003c994c2ebSGoldwyn Rodrigues 				"version of dlm_controld and/or ocfs2-tools."
1004c994c2ebSGoldwyn Rodrigues 				" Please consider upgrading.\n");
1005c994c2ebSGoldwyn Rodrigues 	} else if (ops_rv) {
1006c994c2ebSGoldwyn Rodrigues 		rc = ops_rv;
1007c994c2ebSGoldwyn Rodrigues 		goto out;
1008c994c2ebSGoldwyn Rodrigues 	}
1009c994c2ebSGoldwyn Rodrigues 	conn->cc_lockspace = fsdlm;
1010c994c2ebSGoldwyn Rodrigues 
101124aa3386SGoldwyn Rodrigues 	rc = ocfs2_live_connection_attach(conn, lc);
1012cf4d8d75SDavid Teigland 	if (rc)
1013cf4d8d75SDavid Teigland 		goto out;
1014cf4d8d75SDavid Teigland 
1015c994c2ebSGoldwyn Rodrigues 	if (lc->oc_type == NO_CONTROLD) {
1016c994c2ebSGoldwyn Rodrigues 		rc = get_protocol_version(conn);
1017c994c2ebSGoldwyn Rodrigues 		if (rc) {
1018c994c2ebSGoldwyn Rodrigues 			printk(KERN_ERR "ocfs2: Could not determine"
1019c994c2ebSGoldwyn Rodrigues 					" locking version\n");
1020c994c2ebSGoldwyn Rodrigues 			user_cluster_disconnect(conn);
1021c994c2ebSGoldwyn Rodrigues 			goto out;
1022c994c2ebSGoldwyn Rodrigues 		}
1023c994c2ebSGoldwyn Rodrigues 		wait_event(lc->oc_wait, (atomic_read(&lc->oc_this_node) > 0));
1024c994c2ebSGoldwyn Rodrigues 	}
1025c994c2ebSGoldwyn Rodrigues 
1026cf4d8d75SDavid Teigland 	/*
1027cf4d8d75SDavid Teigland 	 * running_proto must have been set before we allowed any mounts
1028cf4d8d75SDavid Teigland 	 * to proceed.
1029cf4d8d75SDavid Teigland 	 */
1030cf4d8d75SDavid Teigland 	if (fs_protocol_compare(&running_proto, &conn->cc_version)) {
1031cf4d8d75SDavid Teigland 		printk(KERN_ERR
1032cf4d8d75SDavid Teigland 		       "Unable to mount with fs locking protocol version "
1033c994c2ebSGoldwyn Rodrigues 		       "%u.%u because negotiated protocol is %u.%u\n",
1034cf4d8d75SDavid Teigland 		       conn->cc_version.pv_major, conn->cc_version.pv_minor,
1035cf4d8d75SDavid Teigland 		       running_proto.pv_major, running_proto.pv_minor);
1036cf4d8d75SDavid Teigland 		rc = -EPROTO;
103724aa3386SGoldwyn Rodrigues 		ocfs2_live_connection_drop(lc);
103824aa3386SGoldwyn Rodrigues 		lc = NULL;
1039cf4d8d75SDavid Teigland 	}
1040cf4d8d75SDavid Teigland 
1041cf4d8d75SDavid Teigland out:
1042fd90d4dfSMarkus Elfring 	if (rc)
104324aa3386SGoldwyn Rodrigues 		kfree(lc);
1044cf4d8d75SDavid Teigland 	return rc;
1045cf4d8d75SDavid Teigland }
1046cf4d8d75SDavid Teigland 
1047cf4d8d75SDavid Teigland 
user_cluster_this_node(struct ocfs2_cluster_connection * conn,unsigned int * this_node)10483e834151SGoldwyn Rodrigues static int user_cluster_this_node(struct ocfs2_cluster_connection *conn,
10493e834151SGoldwyn Rodrigues 				  unsigned int *this_node)
1050cf4d8d75SDavid Teigland {
1051cf4d8d75SDavid Teigland 	int rc;
10523e834151SGoldwyn Rodrigues 	struct ocfs2_live_connection *lc = conn->cc_private;
1053cf4d8d75SDavid Teigland 
10543e834151SGoldwyn Rodrigues 	if (lc->oc_type == WITH_CONTROLD)
1055cf4d8d75SDavid Teigland 		rc = ocfs2_control_get_this_node();
1056c994c2ebSGoldwyn Rodrigues 	else if (lc->oc_type == NO_CONTROLD)
1057c994c2ebSGoldwyn Rodrigues 		rc = atomic_read(&lc->oc_this_node);
10583e834151SGoldwyn Rodrigues 	else
10593e834151SGoldwyn Rodrigues 		rc = -EINVAL;
1060c994c2ebSGoldwyn Rodrigues 
1061cf4d8d75SDavid Teigland 	if (rc < 0)
1062cf4d8d75SDavid Teigland 		return rc;
1063cf4d8d75SDavid Teigland 
1064cf4d8d75SDavid Teigland 	*this_node = rc;
1065cf4d8d75SDavid Teigland 	return 0;
1066cf4d8d75SDavid Teigland }
1067cf4d8d75SDavid Teigland 
1068a12630b1SJoel Becker static struct ocfs2_stack_operations ocfs2_user_plugin_ops = {
1069cf4d8d75SDavid Teigland 	.connect	= user_cluster_connect,
1070cf4d8d75SDavid Teigland 	.disconnect	= user_cluster_disconnect,
1071cf4d8d75SDavid Teigland 	.this_node	= user_cluster_this_node,
1072cf4d8d75SDavid Teigland 	.dlm_lock	= user_dlm_lock,
1073cf4d8d75SDavid Teigland 	.dlm_unlock	= user_dlm_unlock,
1074cf4d8d75SDavid Teigland 	.lock_status	= user_dlm_lock_status,
10751c520dfbSJoel Becker 	.lvb_valid	= user_dlm_lvb_valid,
1076cf4d8d75SDavid Teigland 	.lock_lvb	= user_dlm_lvb,
107753da4939SMark Fasheh 	.plock		= user_plock,
1078cf4d8d75SDavid Teigland 	.dump_lksb	= user_dlm_dump_lksb,
1079cf4d8d75SDavid Teigland };
1080cf4d8d75SDavid Teigland 
1081a12630b1SJoel Becker static struct ocfs2_stack_plugin ocfs2_user_plugin = {
1082cf4d8d75SDavid Teigland 	.sp_name	= "user",
1083a12630b1SJoel Becker 	.sp_ops		= &ocfs2_user_plugin_ops,
1084cf4d8d75SDavid Teigland 	.sp_owner	= THIS_MODULE,
1085cf4d8d75SDavid Teigland };
1086cf4d8d75SDavid Teigland 
1087cf4d8d75SDavid Teigland 
ocfs2_user_plugin_init(void)1088a12630b1SJoel Becker static int __init ocfs2_user_plugin_init(void)
10896427a727SJoel Becker {
1090cf4d8d75SDavid Teigland 	int rc;
1091cf4d8d75SDavid Teigland 
1092cf4d8d75SDavid Teigland 	rc = ocfs2_control_init();
1093cf4d8d75SDavid Teigland 	if (!rc) {
1094a12630b1SJoel Becker 		rc = ocfs2_stack_glue_register(&ocfs2_user_plugin);
1095cf4d8d75SDavid Teigland 		if (rc)
1096cf4d8d75SDavid Teigland 			ocfs2_control_exit();
1097cf4d8d75SDavid Teigland 	}
1098cf4d8d75SDavid Teigland 
1099cf4d8d75SDavid Teigland 	return rc;
11006427a727SJoel Becker }
11016427a727SJoel Becker 
ocfs2_user_plugin_exit(void)1102a12630b1SJoel Becker static void __exit ocfs2_user_plugin_exit(void)
11038adf0536SJoel Becker {
1104a12630b1SJoel Becker 	ocfs2_stack_glue_unregister(&ocfs2_user_plugin);
11056427a727SJoel Becker 	ocfs2_control_exit();
11068adf0536SJoel Becker }
11078adf0536SJoel Becker 
11088adf0536SJoel Becker MODULE_AUTHOR("Oracle");
11098adf0536SJoel Becker MODULE_DESCRIPTION("ocfs2 driver for userspace cluster stacks");
11108adf0536SJoel Becker MODULE_LICENSE("GPL");
1111a12630b1SJoel Becker module_init(ocfs2_user_plugin_init);
1112a12630b1SJoel Becker module_exit(ocfs2_user_plugin_exit);
1113