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