xref: /openbmc/linux/fs/ocfs2/stackglue.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fa60ce2cSMasahiro Yamada /*
324ef1815SJoel Becker  * stackglue.c
424ef1815SJoel Becker  *
524ef1815SJoel Becker  * Code which implements an OCFS2 specific interface to underlying
624ef1815SJoel Becker  * cluster stacks.
724ef1815SJoel Becker  *
81c520dfbSJoel Becker  * Copyright (C) 2007, 2009 Oracle.  All rights reserved.
924ef1815SJoel Becker  */
1024ef1815SJoel Becker 
11286eaa95SJoel Becker #include <linux/list.h>
12286eaa95SJoel Becker #include <linux/spinlock.h>
13286eaa95SJoel Becker #include <linux/module.h>
144670c46dSJoel Becker #include <linux/slab.h>
156953b4c0SJoel Becker #include <linux/kmod.h>
1674ae4e10SJoel Becker #include <linux/fs.h>
1774ae4e10SJoel Becker #include <linux/kobject.h>
1874ae4e10SJoel Becker #include <linux/sysfs.h>
193878f110SJoel Becker #include <linux/sysctl.h>
204670c46dSJoel Becker 
219c6c877cSJoel Becker #include "ocfs2_fs.h"
229c6c877cSJoel Becker 
2324ef1815SJoel Becker #include "stackglue.h"
2424ef1815SJoel Becker 
259c6c877cSJoel Becker #define OCFS2_STACK_PLUGIN_O2CB		"o2cb"
269c6c877cSJoel Becker #define OCFS2_STACK_PLUGIN_USER		"user"
279f9a99f4SJoel Becker #define OCFS2_MAX_HB_CTL_PATH		256
289c6c877cSJoel Becker 
29553b5eb9SJoel Becker static struct ocfs2_protocol_version locking_max_version;
30286eaa95SJoel Becker static DEFINE_SPINLOCK(ocfs2_stack_lock);
31286eaa95SJoel Becker static LIST_HEAD(ocfs2_stack_list);
329c6c877cSJoel Becker static char cluster_stack_name[OCFS2_STACK_LABEL_LEN + 1];
339f9a99f4SJoel Becker static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
34286eaa95SJoel Becker 
35286eaa95SJoel Becker /*
36286eaa95SJoel Becker  * The stack currently in use.  If not null, active_stack->sp_count > 0,
37286eaa95SJoel Becker  * the module is pinned, and the locking protocol cannot be changed.
38286eaa95SJoel Becker  */
39286eaa95SJoel Becker static struct ocfs2_stack_plugin *active_stack;
40286eaa95SJoel Becker 
ocfs2_stack_lookup(const char * name)41286eaa95SJoel Becker static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name)
42286eaa95SJoel Becker {
43286eaa95SJoel Becker 	struct ocfs2_stack_plugin *p;
44286eaa95SJoel Becker 
45286eaa95SJoel Becker 	assert_spin_locked(&ocfs2_stack_lock);
46286eaa95SJoel Becker 
47286eaa95SJoel Becker 	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
48286eaa95SJoel Becker 		if (!strcmp(p->sp_name, name))
49286eaa95SJoel Becker 			return p;
50286eaa95SJoel Becker 	}
51286eaa95SJoel Becker 
52286eaa95SJoel Becker 	return NULL;
53286eaa95SJoel Becker }
54286eaa95SJoel Becker 
ocfs2_stack_driver_request(const char * stack_name,const char * plugin_name)559c6c877cSJoel Becker static int ocfs2_stack_driver_request(const char *stack_name,
569c6c877cSJoel Becker 				      const char *plugin_name)
57286eaa95SJoel Becker {
58286eaa95SJoel Becker 	int rc;
59286eaa95SJoel Becker 	struct ocfs2_stack_plugin *p;
60286eaa95SJoel Becker 
61286eaa95SJoel Becker 	spin_lock(&ocfs2_stack_lock);
62286eaa95SJoel Becker 
639c6c877cSJoel Becker 	/*
649c6c877cSJoel Becker 	 * If the stack passed by the filesystem isn't the selected one,
659c6c877cSJoel Becker 	 * we can't continue.
669c6c877cSJoel Becker 	 */
679c6c877cSJoel Becker 	if (strcmp(stack_name, cluster_stack_name)) {
689c6c877cSJoel Becker 		rc = -EBUSY;
699c6c877cSJoel Becker 		goto out;
709c6c877cSJoel Becker 	}
719c6c877cSJoel Becker 
72286eaa95SJoel Becker 	if (active_stack) {
73286eaa95SJoel Becker 		/*
74286eaa95SJoel Becker 		 * If the active stack isn't the one we want, it cannot
75286eaa95SJoel Becker 		 * be selected right now.
76286eaa95SJoel Becker 		 */
779c6c877cSJoel Becker 		if (!strcmp(active_stack->sp_name, plugin_name))
78286eaa95SJoel Becker 			rc = 0;
79286eaa95SJoel Becker 		else
80286eaa95SJoel Becker 			rc = -EBUSY;
81286eaa95SJoel Becker 		goto out;
82286eaa95SJoel Becker 	}
83286eaa95SJoel Becker 
849c6c877cSJoel Becker 	p = ocfs2_stack_lookup(plugin_name);
85286eaa95SJoel Becker 	if (!p || !try_module_get(p->sp_owner)) {
86286eaa95SJoel Becker 		rc = -ENOENT;
87286eaa95SJoel Becker 		goto out;
88286eaa95SJoel Becker 	}
89286eaa95SJoel Becker 
90286eaa95SJoel Becker 	active_stack = p;
91286eaa95SJoel Becker 	rc = 0;
92286eaa95SJoel Becker 
93286eaa95SJoel Becker out:
94d6817cdbSJoel Becker 	/* If we found it, pin it */
95d6817cdbSJoel Becker 	if (!rc)
96d6817cdbSJoel Becker 		active_stack->sp_count++;
97d6817cdbSJoel Becker 
98286eaa95SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
99286eaa95SJoel Becker 	return rc;
100286eaa95SJoel Becker }
101286eaa95SJoel Becker 
102286eaa95SJoel Becker /*
103286eaa95SJoel Becker  * This function looks up the appropriate stack and makes it active.  If
104286eaa95SJoel Becker  * there is no stack, it tries to load it.  It will fail if the stack still
105286eaa95SJoel Becker  * cannot be found.  It will also fail if a different stack is in use.
106286eaa95SJoel Becker  */
ocfs2_stack_driver_get(const char * stack_name)1079c6c877cSJoel Becker static int ocfs2_stack_driver_get(const char *stack_name)
108286eaa95SJoel Becker {
109286eaa95SJoel Becker 	int rc;
1109c6c877cSJoel Becker 	char *plugin_name = OCFS2_STACK_PLUGIN_O2CB;
111286eaa95SJoel Becker 
1129c6c877cSJoel Becker 	/*
1139c6c877cSJoel Becker 	 * Classic stack does not pass in a stack name.  This is
1149c6c877cSJoel Becker 	 * compatible with older tools as well.
1159c6c877cSJoel Becker 	 */
1169c6c877cSJoel Becker 	if (!stack_name || !*stack_name)
1179c6c877cSJoel Becker 		stack_name = OCFS2_STACK_PLUGIN_O2CB;
1189c6c877cSJoel Becker 
1199c6c877cSJoel Becker 	if (strlen(stack_name) != OCFS2_STACK_LABEL_LEN) {
1209c6c877cSJoel Becker 		printk(KERN_ERR
1219c6c877cSJoel Becker 		       "ocfs2 passed an invalid cluster stack label: \"%s\"\n",
1229c6c877cSJoel Becker 		       stack_name);
1239c6c877cSJoel Becker 		return -EINVAL;
1249c6c877cSJoel Becker 	}
1259c6c877cSJoel Becker 
1269c6c877cSJoel Becker 	/* Anything that isn't the classic stack is a user stack */
1279c6c877cSJoel Becker 	if (strcmp(stack_name, OCFS2_STACK_PLUGIN_O2CB))
1289c6c877cSJoel Becker 		plugin_name = OCFS2_STACK_PLUGIN_USER;
1299c6c877cSJoel Becker 
1309c6c877cSJoel Becker 	rc = ocfs2_stack_driver_request(stack_name, plugin_name);
131286eaa95SJoel Becker 	if (rc == -ENOENT) {
1329c6c877cSJoel Becker 		request_module("ocfs2_stack_%s", plugin_name);
1339c6c877cSJoel Becker 		rc = ocfs2_stack_driver_request(stack_name, plugin_name);
134286eaa95SJoel Becker 	}
135286eaa95SJoel Becker 
136286eaa95SJoel Becker 	if (rc == -ENOENT) {
137286eaa95SJoel Becker 		printk(KERN_ERR
138286eaa95SJoel Becker 		       "ocfs2: Cluster stack driver \"%s\" cannot be found\n",
1399c6c877cSJoel Becker 		       plugin_name);
140286eaa95SJoel Becker 	} else if (rc == -EBUSY) {
141286eaa95SJoel Becker 		printk(KERN_ERR
1429c6c877cSJoel Becker 		       "ocfs2: A different cluster stack is in use\n");
143286eaa95SJoel Becker 	}
144286eaa95SJoel Becker 
145286eaa95SJoel Becker 	return rc;
146286eaa95SJoel Becker }
147286eaa95SJoel Becker 
ocfs2_stack_driver_put(void)148286eaa95SJoel Becker static void ocfs2_stack_driver_put(void)
149286eaa95SJoel Becker {
150286eaa95SJoel Becker 	spin_lock(&ocfs2_stack_lock);
151286eaa95SJoel Becker 	BUG_ON(active_stack == NULL);
152286eaa95SJoel Becker 	BUG_ON(active_stack->sp_count == 0);
153286eaa95SJoel Becker 
154286eaa95SJoel Becker 	active_stack->sp_count--;
155286eaa95SJoel Becker 	if (!active_stack->sp_count) {
156286eaa95SJoel Becker 		module_put(active_stack->sp_owner);
157286eaa95SJoel Becker 		active_stack = NULL;
158286eaa95SJoel Becker 	}
159286eaa95SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
160286eaa95SJoel Becker }
161286eaa95SJoel Becker 
ocfs2_stack_glue_register(struct ocfs2_stack_plugin * plugin)162286eaa95SJoel Becker int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin)
163286eaa95SJoel Becker {
164286eaa95SJoel Becker 	int rc;
165286eaa95SJoel Becker 
166286eaa95SJoel Becker 	spin_lock(&ocfs2_stack_lock);
167286eaa95SJoel Becker 	if (!ocfs2_stack_lookup(plugin->sp_name)) {
168286eaa95SJoel Becker 		plugin->sp_count = 0;
169553b5eb9SJoel Becker 		plugin->sp_max_proto = locking_max_version;
170286eaa95SJoel Becker 		list_add(&plugin->sp_list, &ocfs2_stack_list);
171286eaa95SJoel Becker 		printk(KERN_INFO "ocfs2: Registered cluster interface %s\n",
172286eaa95SJoel Becker 		       plugin->sp_name);
173286eaa95SJoel Becker 		rc = 0;
174286eaa95SJoel Becker 	} else {
175286eaa95SJoel Becker 		printk(KERN_ERR "ocfs2: Stack \"%s\" already registered\n",
176286eaa95SJoel Becker 		       plugin->sp_name);
177286eaa95SJoel Becker 		rc = -EEXIST;
178286eaa95SJoel Becker 	}
179286eaa95SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
180286eaa95SJoel Becker 
181286eaa95SJoel Becker 	return rc;
182286eaa95SJoel Becker }
183286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_stack_glue_register);
184286eaa95SJoel Becker 
ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin * plugin)185286eaa95SJoel Becker void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin)
186286eaa95SJoel Becker {
187286eaa95SJoel Becker 	struct ocfs2_stack_plugin *p;
188286eaa95SJoel Becker 
189286eaa95SJoel Becker 	spin_lock(&ocfs2_stack_lock);
190286eaa95SJoel Becker 	p = ocfs2_stack_lookup(plugin->sp_name);
191286eaa95SJoel Becker 	if (p) {
192286eaa95SJoel Becker 		BUG_ON(p != plugin);
193286eaa95SJoel Becker 		BUG_ON(plugin == active_stack);
194286eaa95SJoel Becker 		BUG_ON(plugin->sp_count != 0);
195286eaa95SJoel Becker 		list_del_init(&plugin->sp_list);
196286eaa95SJoel Becker 		printk(KERN_INFO "ocfs2: Unregistered cluster interface %s\n",
197286eaa95SJoel Becker 		       plugin->sp_name);
198286eaa95SJoel Becker 	} else {
199286eaa95SJoel Becker 		printk(KERN_ERR "Stack \"%s\" is not registered\n",
200286eaa95SJoel Becker 		       plugin->sp_name);
201286eaa95SJoel Becker 	}
202286eaa95SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
203286eaa95SJoel Becker }
204286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_stack_glue_unregister);
205286eaa95SJoel Becker 
ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version * max_proto)206553b5eb9SJoel Becker void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_proto)
207286eaa95SJoel Becker {
208286eaa95SJoel Becker 	struct ocfs2_stack_plugin *p;
209286eaa95SJoel Becker 
210286eaa95SJoel Becker 	spin_lock(&ocfs2_stack_lock);
211553b5eb9SJoel Becker 	if (memcmp(max_proto, &locking_max_version,
212553b5eb9SJoel Becker 		   sizeof(struct ocfs2_protocol_version))) {
213553b5eb9SJoel Becker 		BUG_ON(locking_max_version.pv_major != 0);
214286eaa95SJoel Becker 
215553b5eb9SJoel Becker 		locking_max_version = *max_proto;
216286eaa95SJoel Becker 		list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
217553b5eb9SJoel Becker 			p->sp_max_proto = locking_max_version;
218286eaa95SJoel Becker 		}
219553b5eb9SJoel Becker 	}
220286eaa95SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
221286eaa95SJoel Becker }
222553b5eb9SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_max_proto_version);
22324ef1815SJoel Becker 
22424ef1815SJoel Becker 
225cf4d8d75SDavid Teigland /*
226a796d286SJoel Becker  * The ocfs2_dlm_lock() and ocfs2_dlm_unlock() functions take no argument
227a796d286SJoel Becker  * for the ast and bast functions.  They will pass the lksb to the ast
228a796d286SJoel Becker  * and bast.  The caller can wrap the lksb with their own structure to
229a796d286SJoel Becker  * get more information.
230cf4d8d75SDavid Teigland  */
ocfs2_dlm_lock(struct ocfs2_cluster_connection * conn,int mode,struct ocfs2_dlm_lksb * lksb,u32 flags,void * name,unsigned int namelen)231553aa7e4SJoel Becker int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn,
232553aa7e4SJoel Becker 		   int mode,
233c0e41338SJoel Becker 		   struct ocfs2_dlm_lksb *lksb,
234553aa7e4SJoel Becker 		   u32 flags,
235553aa7e4SJoel Becker 		   void *name,
236a796d286SJoel Becker 		   unsigned int namelen)
237553aa7e4SJoel Becker {
238c0e41338SJoel Becker 	if (!lksb->lksb_conn)
239c0e41338SJoel Becker 		lksb->lksb_conn = conn;
240c0e41338SJoel Becker 	else
241c0e41338SJoel Becker 		BUG_ON(lksb->lksb_conn != conn);
242286eaa95SJoel Becker 	return active_stack->sp_ops->dlm_lock(conn, mode, lksb, flags,
243a796d286SJoel Becker 					      name, namelen);
244553aa7e4SJoel Becker }
245286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_lock);
246553aa7e4SJoel Becker 
ocfs2_dlm_unlock(struct ocfs2_cluster_connection * conn,struct ocfs2_dlm_lksb * lksb,u32 flags)2474670c46dSJoel Becker int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,
248c0e41338SJoel Becker 		     struct ocfs2_dlm_lksb *lksb,
249a796d286SJoel Becker 		     u32 flags)
25024ef1815SJoel Becker {
251c0e41338SJoel Becker 	BUG_ON(lksb->lksb_conn == NULL);
25224ef1815SJoel Becker 
253a796d286SJoel Becker 	return active_stack->sp_ops->dlm_unlock(conn, lksb, flags);
25424ef1815SJoel Becker }
255286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_unlock);
25624ef1815SJoel Becker 
ocfs2_dlm_lock_status(struct ocfs2_dlm_lksb * lksb)257c0e41338SJoel Becker int ocfs2_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
2588f2c9c1bSJoel Becker {
259286eaa95SJoel Becker 	return active_stack->sp_ops->lock_status(lksb);
2608f2c9c1bSJoel Becker }
261286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status);
2628f2c9c1bSJoel Becker 
ocfs2_dlm_lvb_valid(struct ocfs2_dlm_lksb * lksb)263c0e41338SJoel Becker int ocfs2_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
2641c520dfbSJoel Becker {
2651c520dfbSJoel Becker 	return active_stack->sp_ops->lvb_valid(lksb);
2661c520dfbSJoel Becker }
2671c520dfbSJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid);
2681c520dfbSJoel Becker 
ocfs2_dlm_lvb(struct ocfs2_dlm_lksb * lksb)269c0e41338SJoel Becker void *ocfs2_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
270553aa7e4SJoel Becker {
271286eaa95SJoel Becker 	return active_stack->sp_ops->lock_lvb(lksb);
272cf0acdcdSJoel Becker }
273286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb);
274cf0acdcdSJoel Becker 
ocfs2_dlm_dump_lksb(struct ocfs2_dlm_lksb * lksb)275c0e41338SJoel Becker void ocfs2_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb)
276553aa7e4SJoel Becker {
277286eaa95SJoel Becker 	active_stack->sp_ops->dump_lksb(lksb);
278553aa7e4SJoel Becker }
279286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb);
280553aa7e4SJoel Becker 
ocfs2_stack_supports_plocks(void)28153da4939SMark Fasheh int ocfs2_stack_supports_plocks(void)
28253da4939SMark Fasheh {
283009d3750SMark Fasheh 	return active_stack && active_stack->sp_ops->plock;
28453da4939SMark Fasheh }
28553da4939SMark Fasheh EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks);
28653da4939SMark Fasheh 
28753da4939SMark Fasheh /*
28853da4939SMark Fasheh  * ocfs2_plock() can only be safely called if
28953da4939SMark Fasheh  * ocfs2_stack_supports_plocks() returned true
29053da4939SMark Fasheh  */
ocfs2_plock(struct ocfs2_cluster_connection * conn,u64 ino,struct file * file,int cmd,struct file_lock * fl)29153da4939SMark Fasheh int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
29253da4939SMark Fasheh 		struct file *file, int cmd, struct file_lock *fl)
29353da4939SMark Fasheh {
29453da4939SMark Fasheh 	WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);
29553da4939SMark Fasheh 	if (active_stack->sp_ops->plock)
29653da4939SMark Fasheh 		return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);
29753da4939SMark Fasheh 	return -EOPNOTSUPP;
29853da4939SMark Fasheh }
29953da4939SMark Fasheh EXPORT_SYMBOL_GPL(ocfs2_plock);
30053da4939SMark Fasheh 
ocfs2_cluster_connect(const char * stack_name,const char * cluster_name,int cluster_name_len,const char * group,int grouplen,struct ocfs2_locking_protocol * lproto,void (* recovery_handler)(int node_num,void * recovery_data),void * recovery_data,struct ocfs2_cluster_connection ** conn)3019c6c877cSJoel Becker int ocfs2_cluster_connect(const char *stack_name,
302c74a3bddSGoldwyn Rodrigues 			  const char *cluster_name,
303c74a3bddSGoldwyn Rodrigues 			  int cluster_name_len,
3049c6c877cSJoel Becker 			  const char *group,
3054670c46dSJoel Becker 			  int grouplen,
306553b5eb9SJoel Becker 			  struct ocfs2_locking_protocol *lproto,
3074670c46dSJoel Becker 			  void (*recovery_handler)(int node_num,
3084670c46dSJoel Becker 						   void *recovery_data),
3094670c46dSJoel Becker 			  void *recovery_data,
3104670c46dSJoel Becker 			  struct ocfs2_cluster_connection **conn)
3114670c46dSJoel Becker {
3124670c46dSJoel Becker 	int rc = 0;
3134670c46dSJoel Becker 	struct ocfs2_cluster_connection *new_conn;
3144670c46dSJoel Becker 
3154670c46dSJoel Becker 	BUG_ON(group == NULL);
3164670c46dSJoel Becker 	BUG_ON(conn == NULL);
3174670c46dSJoel Becker 	BUG_ON(recovery_handler == NULL);
3184670c46dSJoel Becker 
3194670c46dSJoel Becker 	if (grouplen > GROUP_NAME_MAX) {
3204670c46dSJoel Becker 		rc = -EINVAL;
3214670c46dSJoel Becker 		goto out;
3224670c46dSJoel Becker 	}
3234670c46dSJoel Becker 
324553b5eb9SJoel Becker 	if (memcmp(&lproto->lp_max_version, &locking_max_version,
325553b5eb9SJoel Becker 		   sizeof(struct ocfs2_protocol_version))) {
326553b5eb9SJoel Becker 		rc = -EINVAL;
327553b5eb9SJoel Becker 		goto out;
328553b5eb9SJoel Becker 	}
329553b5eb9SJoel Becker 
3304670c46dSJoel Becker 	new_conn = kzalloc(sizeof(struct ocfs2_cluster_connection),
3314670c46dSJoel Becker 			   GFP_KERNEL);
3324670c46dSJoel Becker 	if (!new_conn) {
3334670c46dSJoel Becker 		rc = -ENOMEM;
3344670c46dSJoel Becker 		goto out;
3354670c46dSJoel Becker 	}
3364670c46dSJoel Becker 
337c97e21feSWolfram Sang 	strscpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);
3384670c46dSJoel Becker 	new_conn->cc_namelen = grouplen;
339d9060742SSasha Levin 	if (cluster_name_len)
340c97e21feSWolfram Sang 		strscpy(new_conn->cc_cluster_name, cluster_name,
341d9060742SSasha Levin 			CLUSTER_NAME_MAX + 1);
342c74a3bddSGoldwyn Rodrigues 	new_conn->cc_cluster_name_len = cluster_name_len;
3434670c46dSJoel Becker 	new_conn->cc_recovery_handler = recovery_handler;
3444670c46dSJoel Becker 	new_conn->cc_recovery_data = recovery_data;
3454670c46dSJoel Becker 
346110946c8SJoel Becker 	new_conn->cc_proto = lproto;
3474670c46dSJoel Becker 	/* Start the new connection at our maximum compatibility level */
348286eaa95SJoel Becker 	new_conn->cc_version = lproto->lp_max_version;
3494670c46dSJoel Becker 
350286eaa95SJoel Becker 	/* This will pin the stack driver if successful */
3519c6c877cSJoel Becker 	rc = ocfs2_stack_driver_get(stack_name);
352286eaa95SJoel Becker 	if (rc)
353286eaa95SJoel Becker 		goto out_free;
354286eaa95SJoel Becker 
355286eaa95SJoel Becker 	rc = active_stack->sp_ops->connect(new_conn);
356553aa7e4SJoel Becker 	if (rc) {
357286eaa95SJoel Becker 		ocfs2_stack_driver_put();
3584670c46dSJoel Becker 		goto out_free;
3594670c46dSJoel Becker 	}
3604670c46dSJoel Becker 
3614670c46dSJoel Becker 	*conn = new_conn;
3624670c46dSJoel Becker 
3634670c46dSJoel Becker out_free:
364553aa7e4SJoel Becker 	if (rc)
3654670c46dSJoel Becker 		kfree(new_conn);
3664670c46dSJoel Becker 
3674670c46dSJoel Becker out:
3684670c46dSJoel Becker 	return rc;
3694670c46dSJoel Becker }
370286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_cluster_connect);
3714670c46dSJoel Becker 
372cbe0e331SJoel Becker /* The caller will ensure all nodes have the same cluster stack */
ocfs2_cluster_connect_agnostic(const char * group,int grouplen,struct ocfs2_locking_protocol * lproto,void (* recovery_handler)(int node_num,void * recovery_data),void * recovery_data,struct ocfs2_cluster_connection ** conn)373cbe0e331SJoel Becker int ocfs2_cluster_connect_agnostic(const char *group,
374cbe0e331SJoel Becker 				   int grouplen,
375cbe0e331SJoel Becker 				   struct ocfs2_locking_protocol *lproto,
376cbe0e331SJoel Becker 				   void (*recovery_handler)(int node_num,
377cbe0e331SJoel Becker 							    void *recovery_data),
378cbe0e331SJoel Becker 				   void *recovery_data,
379cbe0e331SJoel Becker 				   struct ocfs2_cluster_connection **conn)
380cbe0e331SJoel Becker {
381cbe0e331SJoel Becker 	char *stack_name = NULL;
382cbe0e331SJoel Becker 
383cbe0e331SJoel Becker 	if (cluster_stack_name[0])
384cbe0e331SJoel Becker 		stack_name = cluster_stack_name;
385c74a3bddSGoldwyn Rodrigues 	return ocfs2_cluster_connect(stack_name, NULL, 0, group, grouplen,
386c74a3bddSGoldwyn Rodrigues 				     lproto, recovery_handler, recovery_data,
387c74a3bddSGoldwyn Rodrigues 				     conn);
388cbe0e331SJoel Becker }
389cbe0e331SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_cluster_connect_agnostic);
390cbe0e331SJoel Becker 
391286eaa95SJoel Becker /* If hangup_pending is 0, the stack driver will be dropped */
ocfs2_cluster_disconnect(struct ocfs2_cluster_connection * conn,int hangup_pending)392286eaa95SJoel Becker int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,
393286eaa95SJoel Becker 			     int hangup_pending)
394553aa7e4SJoel Becker {
395553aa7e4SJoel Becker 	int ret;
396553aa7e4SJoel Becker 
397553aa7e4SJoel Becker 	BUG_ON(conn == NULL);
398553aa7e4SJoel Becker 
3992c39450bSJoel Becker 	ret = active_stack->sp_ops->disconnect(conn);
400553aa7e4SJoel Becker 
401553aa7e4SJoel Becker 	/* XXX Should we free it anyway? */
402286eaa95SJoel Becker 	if (!ret) {
403553aa7e4SJoel Becker 		kfree(conn);
404286eaa95SJoel Becker 		if (!hangup_pending)
405286eaa95SJoel Becker 			ocfs2_stack_driver_put();
406286eaa95SJoel Becker 	}
407553aa7e4SJoel Becker 
408553aa7e4SJoel Becker 	return ret;
409553aa7e4SJoel Becker }
410286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_cluster_disconnect);
411553aa7e4SJoel Becker 
4129f9a99f4SJoel Becker /*
4139f9a99f4SJoel Becker  * Leave the group for this filesystem.  This is executed by a userspace
4149f9a99f4SJoel Becker  * program (stored in ocfs2_hb_ctl_path).
4159f9a99f4SJoel Becker  */
ocfs2_leave_group(const char * group)4169f9a99f4SJoel Becker static void ocfs2_leave_group(const char *group)
4179f9a99f4SJoel Becker {
4189f9a99f4SJoel Becker 	int ret;
4199f9a99f4SJoel Becker 	char *argv[5], *envp[3];
4209f9a99f4SJoel Becker 
4219f9a99f4SJoel Becker 	argv[0] = ocfs2_hb_ctl_path;
4229f9a99f4SJoel Becker 	argv[1] = "-K";
4239f9a99f4SJoel Becker 	argv[2] = "-u";
4249f9a99f4SJoel Becker 	argv[3] = (char *)group;
4259f9a99f4SJoel Becker 	argv[4] = NULL;
4269f9a99f4SJoel Becker 
4279f9a99f4SJoel Becker 	/* minimal command environment taken from cpu_run_sbin_hotplug */
4289f9a99f4SJoel Becker 	envp[0] = "HOME=/";
4299f9a99f4SJoel Becker 	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
4309f9a99f4SJoel Becker 	envp[2] = NULL;
4319f9a99f4SJoel Becker 
4329f9a99f4SJoel Becker 	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
4339f9a99f4SJoel Becker 	if (ret < 0) {
4349f9a99f4SJoel Becker 		printk(KERN_ERR
4359f9a99f4SJoel Becker 		       "ocfs2: Error %d running user helper "
4369f9a99f4SJoel Becker 		       "\"%s %s %s %s\"\n",
4379f9a99f4SJoel Becker 		       ret, argv[0], argv[1], argv[2], argv[3]);
4389f9a99f4SJoel Becker 	}
4399f9a99f4SJoel Becker }
4409f9a99f4SJoel Becker 
4419f9a99f4SJoel Becker /*
4429f9a99f4SJoel Becker  * Hangup is a required post-umount.  ocfs2-tools software expects the
4439f9a99f4SJoel Becker  * filesystem to call "ocfs2_hb_ctl" during unmount.  This happens
4449f9a99f4SJoel Becker  * regardless of whether the DLM got started, so we can't do it
4459f9a99f4SJoel Becker  * in ocfs2_cluster_disconnect().  The ocfs2_leave_group() function does
4469f9a99f4SJoel Becker  * the actual work.
4479f9a99f4SJoel Becker  */
ocfs2_cluster_hangup(const char * group,int grouplen)4486953b4c0SJoel Becker void ocfs2_cluster_hangup(const char *group, int grouplen)
4496953b4c0SJoel Becker {
4506953b4c0SJoel Becker 	BUG_ON(group == NULL);
4516953b4c0SJoel Becker 	BUG_ON(group[grouplen] != '\0');
4526953b4c0SJoel Becker 
4539f9a99f4SJoel Becker 	ocfs2_leave_group(group);
4549f9a99f4SJoel Becker 
455286eaa95SJoel Becker 	/* cluster_disconnect() was called with hangup_pending==1 */
456286eaa95SJoel Becker 	ocfs2_stack_driver_put();
45719fdb624SJoel Becker }
458286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_cluster_hangup);
45919fdb624SJoel Becker 
ocfs2_cluster_this_node(struct ocfs2_cluster_connection * conn,unsigned int * node)4603e834151SGoldwyn Rodrigues int ocfs2_cluster_this_node(struct ocfs2_cluster_connection *conn,
4613e834151SGoldwyn Rodrigues 			    unsigned int *node)
462553aa7e4SJoel Becker {
4633e834151SGoldwyn Rodrigues 	return active_stack->sp_ops->this_node(conn, node);
464553aa7e4SJoel Becker }
465286eaa95SJoel Becker EXPORT_SYMBOL_GPL(ocfs2_cluster_this_node);
466553aa7e4SJoel Becker 
467286eaa95SJoel Becker 
46874ae4e10SJoel Becker /*
46974ae4e10SJoel Becker  * Sysfs bits
47074ae4e10SJoel Becker  */
47174ae4e10SJoel Becker 
ocfs2_max_locking_protocol_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)47274ae4e10SJoel Becker static ssize_t ocfs2_max_locking_protocol_show(struct kobject *kobj,
47374ae4e10SJoel Becker 					       struct kobj_attribute *attr,
47474ae4e10SJoel Becker 					       char *buf)
47574ae4e10SJoel Becker {
47674ae4e10SJoel Becker 	ssize_t ret = 0;
47774ae4e10SJoel Becker 
47874ae4e10SJoel Becker 	spin_lock(&ocfs2_stack_lock);
479553b5eb9SJoel Becker 	if (locking_max_version.pv_major)
48074ae4e10SJoel Becker 		ret = snprintf(buf, PAGE_SIZE, "%u.%u\n",
481553b5eb9SJoel Becker 			       locking_max_version.pv_major,
482553b5eb9SJoel Becker 			       locking_max_version.pv_minor);
48374ae4e10SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
48474ae4e10SJoel Becker 
48574ae4e10SJoel Becker 	return ret;
48674ae4e10SJoel Becker }
48774ae4e10SJoel Becker 
48874ae4e10SJoel Becker static struct kobj_attribute ocfs2_attr_max_locking_protocol =
48958f86cc8SRusty Russell 	__ATTR(max_locking_protocol, S_IRUGO,
49074ae4e10SJoel Becker 	       ocfs2_max_locking_protocol_show, NULL);
49174ae4e10SJoel Becker 
ocfs2_loaded_cluster_plugins_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)49274ae4e10SJoel Becker static ssize_t ocfs2_loaded_cluster_plugins_show(struct kobject *kobj,
49374ae4e10SJoel Becker 						 struct kobj_attribute *attr,
49474ae4e10SJoel Becker 						 char *buf)
49574ae4e10SJoel Becker {
49674ae4e10SJoel Becker 	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
49774ae4e10SJoel Becker 	struct ocfs2_stack_plugin *p;
49874ae4e10SJoel Becker 
49974ae4e10SJoel Becker 	spin_lock(&ocfs2_stack_lock);
50074ae4e10SJoel Becker 	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
50174ae4e10SJoel Becker 		ret = snprintf(buf, remain, "%s\n",
50274ae4e10SJoel Becker 			       p->sp_name);
50354e948c6SDan Carpenter 		if (ret >= remain) {
50474ae4e10SJoel Becker 			/* snprintf() didn't fit */
50574ae4e10SJoel Becker 			total = -E2BIG;
50674ae4e10SJoel Becker 			break;
50774ae4e10SJoel Becker 		}
50874ae4e10SJoel Becker 		total += ret;
50974ae4e10SJoel Becker 		remain -= ret;
51074ae4e10SJoel Becker 	}
51174ae4e10SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
51274ae4e10SJoel Becker 
51374ae4e10SJoel Becker 	return total;
51474ae4e10SJoel Becker }
51574ae4e10SJoel Becker 
51674ae4e10SJoel Becker static struct kobj_attribute ocfs2_attr_loaded_cluster_plugins =
51758f86cc8SRusty Russell 	__ATTR(loaded_cluster_plugins, S_IRUGO,
51874ae4e10SJoel Becker 	       ocfs2_loaded_cluster_plugins_show, NULL);
51974ae4e10SJoel Becker 
ocfs2_active_cluster_plugin_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)52074ae4e10SJoel Becker static ssize_t ocfs2_active_cluster_plugin_show(struct kobject *kobj,
52174ae4e10SJoel Becker 						struct kobj_attribute *attr,
52274ae4e10SJoel Becker 						char *buf)
52374ae4e10SJoel Becker {
52474ae4e10SJoel Becker 	ssize_t ret = 0;
52574ae4e10SJoel Becker 
52674ae4e10SJoel Becker 	spin_lock(&ocfs2_stack_lock);
52774ae4e10SJoel Becker 	if (active_stack) {
52874ae4e10SJoel Becker 		ret = snprintf(buf, PAGE_SIZE, "%s\n",
52974ae4e10SJoel Becker 			       active_stack->sp_name);
53054e948c6SDan Carpenter 		if (ret >= PAGE_SIZE)
53174ae4e10SJoel Becker 			ret = -E2BIG;
53274ae4e10SJoel Becker 	}
53374ae4e10SJoel Becker 	spin_unlock(&ocfs2_stack_lock);
53474ae4e10SJoel Becker 
53574ae4e10SJoel Becker 	return ret;
53674ae4e10SJoel Becker }
53774ae4e10SJoel Becker 
53874ae4e10SJoel Becker static struct kobj_attribute ocfs2_attr_active_cluster_plugin =
53958f86cc8SRusty Russell 	__ATTR(active_cluster_plugin, S_IRUGO,
54074ae4e10SJoel Becker 	       ocfs2_active_cluster_plugin_show, NULL);
54174ae4e10SJoel Becker 
ocfs2_cluster_stack_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)5429c6c877cSJoel Becker static ssize_t ocfs2_cluster_stack_show(struct kobject *kobj,
5439c6c877cSJoel Becker 					struct kobj_attribute *attr,
5449c6c877cSJoel Becker 					char *buf)
5459c6c877cSJoel Becker {
5469c6c877cSJoel Becker 	ssize_t ret;
5479c6c877cSJoel Becker 	spin_lock(&ocfs2_stack_lock);
5489c6c877cSJoel Becker 	ret = snprintf(buf, PAGE_SIZE, "%s\n", cluster_stack_name);
5499c6c877cSJoel Becker 	spin_unlock(&ocfs2_stack_lock);
5509c6c877cSJoel Becker 
5519c6c877cSJoel Becker 	return ret;
5529c6c877cSJoel Becker }
5539c6c877cSJoel Becker 
ocfs2_cluster_stack_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)5549c6c877cSJoel Becker static ssize_t ocfs2_cluster_stack_store(struct kobject *kobj,
5559c6c877cSJoel Becker 					 struct kobj_attribute *attr,
5569c6c877cSJoel Becker 					 const char *buf, size_t count)
5579c6c877cSJoel Becker {
5589c6c877cSJoel Becker 	size_t len = count;
5599c6c877cSJoel Becker 	ssize_t ret;
5609c6c877cSJoel Becker 
5619c6c877cSJoel Becker 	if (len == 0)
5629c6c877cSJoel Becker 		return len;
5639c6c877cSJoel Becker 
5649c6c877cSJoel Becker 	if (buf[len - 1] == '\n')
5659c6c877cSJoel Becker 		len--;
5669c6c877cSJoel Becker 
5679c6c877cSJoel Becker 	if ((len != OCFS2_STACK_LABEL_LEN) ||
5689c6c877cSJoel Becker 	    (strnlen(buf, len) != len))
5699c6c877cSJoel Becker 		return -EINVAL;
5709c6c877cSJoel Becker 
5719c6c877cSJoel Becker 	spin_lock(&ocfs2_stack_lock);
5729c6c877cSJoel Becker 	if (active_stack) {
5739c6c877cSJoel Becker 		if (!strncmp(buf, cluster_stack_name, len))
5749c6c877cSJoel Becker 			ret = count;
5759c6c877cSJoel Becker 		else
5769c6c877cSJoel Becker 			ret = -EBUSY;
5779c6c877cSJoel Becker 	} else {
5789c6c877cSJoel Becker 		memcpy(cluster_stack_name, buf, len);
5799c6c877cSJoel Becker 		ret = count;
5809c6c877cSJoel Becker 	}
5819c6c877cSJoel Becker 	spin_unlock(&ocfs2_stack_lock);
5829c6c877cSJoel Becker 
5839c6c877cSJoel Becker 	return ret;
5849c6c877cSJoel Becker }
5859c6c877cSJoel Becker 
5869c6c877cSJoel Becker 
5879c6c877cSJoel Becker static struct kobj_attribute ocfs2_attr_cluster_stack =
58858f86cc8SRusty Russell 	__ATTR(cluster_stack, S_IRUGO | S_IWUSR,
5899c6c877cSJoel Becker 	       ocfs2_cluster_stack_show,
5909c6c877cSJoel Becker 	       ocfs2_cluster_stack_store);
5919c6c877cSJoel Becker 
592765aabbbSGoldwyn Rodrigues 
593765aabbbSGoldwyn Rodrigues 
ocfs2_dlm_recover_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)594765aabbbSGoldwyn Rodrigues static ssize_t ocfs2_dlm_recover_show(struct kobject *kobj,
595765aabbbSGoldwyn Rodrigues 					struct kobj_attribute *attr,
596765aabbbSGoldwyn Rodrigues 					char *buf)
597765aabbbSGoldwyn Rodrigues {
598765aabbbSGoldwyn Rodrigues 	return snprintf(buf, PAGE_SIZE, "1\n");
599765aabbbSGoldwyn Rodrigues }
600765aabbbSGoldwyn Rodrigues 
601765aabbbSGoldwyn Rodrigues static struct kobj_attribute ocfs2_attr_dlm_recover_support =
602765aabbbSGoldwyn Rodrigues 	__ATTR(dlm_recover_callback_support, S_IRUGO,
603765aabbbSGoldwyn Rodrigues 	       ocfs2_dlm_recover_show, NULL);
604765aabbbSGoldwyn Rodrigues 
60574ae4e10SJoel Becker static struct attribute *ocfs2_attrs[] = {
60674ae4e10SJoel Becker 	&ocfs2_attr_max_locking_protocol.attr,
60774ae4e10SJoel Becker 	&ocfs2_attr_loaded_cluster_plugins.attr,
60874ae4e10SJoel Becker 	&ocfs2_attr_active_cluster_plugin.attr,
6099c6c877cSJoel Becker 	&ocfs2_attr_cluster_stack.attr,
610765aabbbSGoldwyn Rodrigues 	&ocfs2_attr_dlm_recover_support.attr,
61174ae4e10SJoel Becker 	NULL,
61274ae4e10SJoel Becker };
61374ae4e10SJoel Becker 
614b74271e4SArvind Yadav static const struct attribute_group ocfs2_attr_group = {
61574ae4e10SJoel Becker 	.attrs = ocfs2_attrs,
61674ae4e10SJoel Becker };
61774ae4e10SJoel Becker 
6189dde5e4fSGang He struct kset *ocfs2_kset;
6199dde5e4fSGang He EXPORT_SYMBOL_GPL(ocfs2_kset);
62074ae4e10SJoel Becker 
ocfs2_sysfs_exit(void)62174ae4e10SJoel Becker static void ocfs2_sysfs_exit(void)
62274ae4e10SJoel Becker {
62374ae4e10SJoel Becker 	kset_unregister(ocfs2_kset);
62474ae4e10SJoel Becker }
62574ae4e10SJoel Becker 
ocfs2_sysfs_init(void)62674ae4e10SJoel Becker static int ocfs2_sysfs_init(void)
62774ae4e10SJoel Becker {
62874ae4e10SJoel Becker 	int ret;
62974ae4e10SJoel Becker 
63074ae4e10SJoel Becker 	ocfs2_kset = kset_create_and_add("ocfs2", NULL, fs_kobj);
63174ae4e10SJoel Becker 	if (!ocfs2_kset)
63274ae4e10SJoel Becker 		return -ENOMEM;
63374ae4e10SJoel Becker 
63474ae4e10SJoel Becker 	ret = sysfs_create_group(&ocfs2_kset->kobj, &ocfs2_attr_group);
63574ae4e10SJoel Becker 	if (ret)
63674ae4e10SJoel Becker 		goto error;
63774ae4e10SJoel Becker 
63874ae4e10SJoel Becker 	return 0;
63974ae4e10SJoel Becker 
64074ae4e10SJoel Becker error:
64174ae4e10SJoel Becker 	kset_unregister(ocfs2_kset);
64274ae4e10SJoel Becker 	return ret;
64374ae4e10SJoel Becker }
64474ae4e10SJoel Becker 
6453878f110SJoel Becker /*
6463878f110SJoel Becker  * Sysctl bits
6473878f110SJoel Becker  *
6483878f110SJoel Becker  * The sysctl lives at /proc/sys/fs/ocfs2/nm/hb_ctl_path.  The 'nm' doesn't
6493878f110SJoel Becker  * make as much sense in a multiple cluster stack world, but it's safer
6503878f110SJoel Becker  * and easier to preserve the name.
6513878f110SJoel Becker  */
6523878f110SJoel Becker 
653d00d2f8aSJoe Perches static struct ctl_table ocfs2_nm_table[] = {
6543878f110SJoel Becker 	{
6553878f110SJoel Becker 		.procname	= "hb_ctl_path",
6563878f110SJoel Becker 		.data		= ocfs2_hb_ctl_path,
6573878f110SJoel Becker 		.maxlen		= OCFS2_MAX_HB_CTL_PATH,
6583878f110SJoel Becker 		.mode		= 0644,
6596d456111SEric W. Biederman 		.proc_handler	= proc_dostring,
6603878f110SJoel Becker 	},
661ab09203eSEric W. Biederman 	{ }
6623878f110SJoel Becker };
6633878f110SJoel Becker 
6641a5c4e2aSFabian Frederick static struct ctl_table_header *ocfs2_table_header;
6653878f110SJoel Becker 
6663878f110SJoel Becker /*
6673878f110SJoel Becker  * Initialization
6683878f110SJoel Becker  */
6693878f110SJoel Becker 
ocfs2_stack_glue_init(void)670286eaa95SJoel Becker static int __init ocfs2_stack_glue_init(void)
67124ef1815SJoel Becker {
672*13b6269dSShang XiaoJing 	int ret;
673*13b6269dSShang XiaoJing 
6749c6c877cSJoel Becker 	strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
6759c6c877cSJoel Becker 
676f6a26318SLinus Torvalds 	ocfs2_table_header = register_sysctl("fs/ocfs2/nm", ocfs2_nm_table);
6773878f110SJoel Becker 	if (!ocfs2_table_header) {
6783878f110SJoel Becker 		printk(KERN_ERR
6793878f110SJoel Becker 		       "ocfs2 stack glue: unable to register sysctl\n");
6803878f110SJoel Becker 		return -ENOMEM; /* or something. */
6813878f110SJoel Becker 	}
6823878f110SJoel Becker 
683*13b6269dSShang XiaoJing 	ret = ocfs2_sysfs_init();
684*13b6269dSShang XiaoJing 	if (ret)
685*13b6269dSShang XiaoJing 		unregister_sysctl_table(ocfs2_table_header);
686*13b6269dSShang XiaoJing 
687*13b6269dSShang XiaoJing 	return ret;
68824ef1815SJoel Becker }
68924ef1815SJoel Becker 
ocfs2_stack_glue_exit(void)690286eaa95SJoel Becker static void __exit ocfs2_stack_glue_exit(void)
691286eaa95SJoel Becker {
692553b5eb9SJoel Becker 	memset(&locking_max_version, 0,
693553b5eb9SJoel Becker 	       sizeof(struct ocfs2_protocol_version));
69474ae4e10SJoel Becker 	ocfs2_sysfs_exit();
6953878f110SJoel Becker 	if (ocfs2_table_header)
6963878f110SJoel Becker 		unregister_sysctl_table(ocfs2_table_header);
697286eaa95SJoel Becker }
698286eaa95SJoel Becker 
699286eaa95SJoel Becker MODULE_AUTHOR("Oracle");
700f13604a2SBhaskar Chowdhury MODULE_DESCRIPTION("ocfs2 cluster stack glue layer");
701286eaa95SJoel Becker MODULE_LICENSE("GPL");
702286eaa95SJoel Becker module_init(ocfs2_stack_glue_init);
703286eaa95SJoel Becker module_exit(ocfs2_stack_glue_exit);
704