701 lines · 16.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * stackglue.c * * Code which implements an OCFS2 specific interface to underlying * cluster stacks. * * Copyright (C) 2007, 2009 Oracle.  All rights reserved. */ #include <linux/list.h>#include <linux/spinlock.h>#include <linux/string.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/fs.h>#include <linux/kobject.h>#include <linux/sysfs.h>#include <linux/sysctl.h> #include "ocfs2_fs.h" #include "stackglue.h" #define OCFS2_STACK_PLUGIN_O2CB		"o2cb"#define OCFS2_STACK_PLUGIN_USER		"user"#define OCFS2_MAX_HB_CTL_PATH		256 static struct ocfs2_protocol_version locking_max_version;static DEFINE_SPINLOCK(ocfs2_stack_lock);static LIST_HEAD(ocfs2_stack_list);static char cluster_stack_name[OCFS2_STACK_LABEL_LEN + 1];static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl"; /* * The stack currently in use.  If not null, active_stack->sp_count > 0, * the module is pinned, and the locking protocol cannot be changed. */static struct ocfs2_stack_plugin *active_stack; static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name){	struct ocfs2_stack_plugin *p; 	assert_spin_locked(&ocfs2_stack_lock); 	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {		if (!strcmp(p->sp_name, name))			return p;	} 	return NULL;} static int ocfs2_stack_driver_request(const char *stack_name,				      const char *plugin_name){	int rc;	struct ocfs2_stack_plugin *p; 	spin_lock(&ocfs2_stack_lock); 	/*	 * If the stack passed by the filesystem isn't the selected one,	 * we can't continue.	 */	if (strcmp(stack_name, cluster_stack_name)) {		rc = -EBUSY;		goto out;	} 	if (active_stack) {		/*		 * If the active stack isn't the one we want, it cannot		 * be selected right now.		 */		if (!strcmp(active_stack->sp_name, plugin_name))			rc = 0;		else			rc = -EBUSY;		goto out;	} 	p = ocfs2_stack_lookup(plugin_name);	if (!p || !try_module_get(p->sp_owner)) {		rc = -ENOENT;		goto out;	} 	active_stack = p;	rc = 0; out:	/* If we found it, pin it */	if (!rc)		active_stack->sp_count++; 	spin_unlock(&ocfs2_stack_lock);	return rc;} /* * This function looks up the appropriate stack and makes it active.  If * there is no stack, it tries to load it.  It will fail if the stack still * cannot be found.  It will also fail if a different stack is in use. */static int ocfs2_stack_driver_get(const char *stack_name){	int rc;	char *plugin_name = OCFS2_STACK_PLUGIN_O2CB; 	/*	 * Classic stack does not pass in a stack name.  This is	 * compatible with older tools as well.	 */	if (!stack_name || !*stack_name)		stack_name = OCFS2_STACK_PLUGIN_O2CB; 	if (strlen(stack_name) != OCFS2_STACK_LABEL_LEN) {		printk(KERN_ERR		       "ocfs2 passed an invalid cluster stack label: \"%s\"\n",		       stack_name);		return -EINVAL;	} 	/* Anything that isn't the classic stack is a user stack */	if (strcmp(stack_name, OCFS2_STACK_PLUGIN_O2CB))		plugin_name = OCFS2_STACK_PLUGIN_USER; 	rc = ocfs2_stack_driver_request(stack_name, plugin_name);	if (rc == -ENOENT) {		request_module("ocfs2_stack_%s", plugin_name);		rc = ocfs2_stack_driver_request(stack_name, plugin_name);	} 	if (rc == -ENOENT) {		printk(KERN_ERR		       "ocfs2: Cluster stack driver \"%s\" cannot be found\n",		       plugin_name);	} else if (rc == -EBUSY) {		printk(KERN_ERR		       "ocfs2: A different cluster stack is in use\n");	} 	return rc;} static void ocfs2_stack_driver_put(void){	spin_lock(&ocfs2_stack_lock);	BUG_ON(active_stack == NULL);	BUG_ON(active_stack->sp_count == 0); 	active_stack->sp_count--;	if (!active_stack->sp_count) {		module_put(active_stack->sp_owner);		active_stack = NULL;	}	spin_unlock(&ocfs2_stack_lock);} int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin){	int rc; 	spin_lock(&ocfs2_stack_lock);	if (!ocfs2_stack_lookup(plugin->sp_name)) {		plugin->sp_count = 0;		plugin->sp_max_proto = locking_max_version;		list_add(&plugin->sp_list, &ocfs2_stack_list);		printk(KERN_INFO "ocfs2: Registered cluster interface %s\n",		       plugin->sp_name);		rc = 0;	} else {		printk(KERN_ERR "ocfs2: Stack \"%s\" already registered\n",		       plugin->sp_name);		rc = -EEXIST;	}	spin_unlock(&ocfs2_stack_lock); 	return rc;}EXPORT_SYMBOL_GPL(ocfs2_stack_glue_register); void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin){	struct ocfs2_stack_plugin *p; 	spin_lock(&ocfs2_stack_lock);	p = ocfs2_stack_lookup(plugin->sp_name);	if (p) {		BUG_ON(p != plugin);		BUG_ON(plugin == active_stack);		BUG_ON(plugin->sp_count != 0);		list_del_init(&plugin->sp_list);		printk(KERN_INFO "ocfs2: Unregistered cluster interface %s\n",		       plugin->sp_name);	} else {		printk(KERN_ERR "Stack \"%s\" is not registered\n",		       plugin->sp_name);	}	spin_unlock(&ocfs2_stack_lock);}EXPORT_SYMBOL_GPL(ocfs2_stack_glue_unregister); void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_proto){	struct ocfs2_stack_plugin *p; 	spin_lock(&ocfs2_stack_lock);	if (memcmp(max_proto, &locking_max_version,		   sizeof(struct ocfs2_protocol_version))) {		BUG_ON(locking_max_version.pv_major != 0); 		locking_max_version = *max_proto;		list_for_each_entry(p, &ocfs2_stack_list, sp_list) {			p->sp_max_proto = locking_max_version;		}	}	spin_unlock(&ocfs2_stack_lock);}EXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_max_proto_version);  /* * The ocfs2_dlm_lock() and ocfs2_dlm_unlock() functions take no argument * for the ast and bast functions.  They will pass the lksb to the ast * and bast.  The caller can wrap the lksb with their own structure to * get more information. */int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn,		   int mode,		   struct ocfs2_dlm_lksb *lksb,		   u32 flags,		   void *name,		   unsigned int namelen){	if (!lksb->lksb_conn)		lksb->lksb_conn = conn;	else		BUG_ON(lksb->lksb_conn != conn);	return active_stack->sp_ops->dlm_lock(conn, mode, lksb, flags,					      name, namelen);}EXPORT_SYMBOL_GPL(ocfs2_dlm_lock); int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,		     struct ocfs2_dlm_lksb *lksb,		     u32 flags){	BUG_ON(lksb->lksb_conn == NULL); 	return active_stack->sp_ops->dlm_unlock(conn, lksb, flags);}EXPORT_SYMBOL_GPL(ocfs2_dlm_unlock); int ocfs2_dlm_lock_status(struct ocfs2_dlm_lksb *lksb){	return active_stack->sp_ops->lock_status(lksb);}EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); int ocfs2_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb){	return active_stack->sp_ops->lvb_valid(lksb);}EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid); void *ocfs2_dlm_lvb(struct ocfs2_dlm_lksb *lksb){	return active_stack->sp_ops->lock_lvb(lksb);}EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb); void ocfs2_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb){	active_stack->sp_ops->dump_lksb(lksb);}EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); int ocfs2_stack_supports_plocks(void){	return active_stack && active_stack->sp_ops->plock;}EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks); /* * ocfs2_plock() can only be safely called if * ocfs2_stack_supports_plocks() returned true */int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,		struct file *file, int cmd, struct file_lock *fl){	WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);	if (active_stack->sp_ops->plock)		return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);	return -EOPNOTSUPP;}EXPORT_SYMBOL_GPL(ocfs2_plock); int 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){	int rc = 0;	struct ocfs2_cluster_connection *new_conn; 	BUG_ON(group == NULL);	BUG_ON(conn == NULL);	BUG_ON(recovery_handler == NULL); 	if (grouplen > GROUP_NAME_MAX) {		rc = -EINVAL;		goto out;	} 	if (memcmp(&lproto->lp_max_version, &locking_max_version,		   sizeof(struct ocfs2_protocol_version))) {		rc = -EINVAL;		goto out;	} 	new_conn = kzalloc_obj(struct ocfs2_cluster_connection);	if (!new_conn) {		rc = -ENOMEM;		goto out;	} 	strscpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);	new_conn->cc_namelen = grouplen;	if (cluster_name_len)		strscpy(new_conn->cc_cluster_name, cluster_name,			CLUSTER_NAME_MAX + 1);	new_conn->cc_cluster_name_len = cluster_name_len;	new_conn->cc_recovery_handler = recovery_handler;	new_conn->cc_recovery_data = recovery_data; 	new_conn->cc_proto = lproto;	/* Start the new connection at our maximum compatibility level */	new_conn->cc_version = lproto->lp_max_version; 	/* This will pin the stack driver if successful */	rc = ocfs2_stack_driver_get(stack_name);	if (rc)		goto out_free; 	rc = active_stack->sp_ops->connect(new_conn);	if (rc) {		ocfs2_stack_driver_put();		goto out_free;	} 	*conn = new_conn; out_free:	if (rc)		kfree(new_conn); out:	return rc;}EXPORT_SYMBOL_GPL(ocfs2_cluster_connect); /* The caller will ensure all nodes have the same cluster stack */int ocfs2_cluster_connect_agnostic(const char *group,				   int grouplen,				   struct ocfs2_locking_protocol *lproto,				   void (*recovery_handler)(int node_num,							    void *recovery_data),				   void *recovery_data,				   struct ocfs2_cluster_connection **conn){	char *stack_name = NULL; 	if (cluster_stack_name[0])		stack_name = cluster_stack_name;	return ocfs2_cluster_connect(stack_name, NULL, 0, group, grouplen,				     lproto, recovery_handler, recovery_data,				     conn);}EXPORT_SYMBOL_GPL(ocfs2_cluster_connect_agnostic); /* If hangup_pending is 0, the stack driver will be dropped */int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,			     int hangup_pending){	int ret; 	BUG_ON(conn == NULL); 	ret = active_stack->sp_ops->disconnect(conn); 	/* XXX Should we free it anyway? */	if (!ret) {		kfree(conn);		if (!hangup_pending)			ocfs2_stack_driver_put();	} 	return ret;}EXPORT_SYMBOL_GPL(ocfs2_cluster_disconnect); /* * Leave the group for this filesystem.  This is executed by a userspace * program (stored in ocfs2_hb_ctl_path). */static void ocfs2_leave_group(const char *group){	int ret;	char *argv[5], *envp[3]; 	argv[0] = ocfs2_hb_ctl_path;	argv[1] = "-K";	argv[2] = "-u";	argv[3] = (char *)group;	argv[4] = NULL; 	/* minimal command environment taken from cpu_run_sbin_hotplug */	envp[0] = "HOME=/";	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";	envp[2] = NULL; 	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);	if (ret < 0) {		printk(KERN_ERR		       "ocfs2: Error %d running user helper "		       "\"%s %s %s %s\"\n",		       ret, argv[0], argv[1], argv[2], argv[3]);	}} /* * Hangup is a required post-umount.  ocfs2-tools software expects the * filesystem to call "ocfs2_hb_ctl" during unmount.  This happens * regardless of whether the DLM got started, so we can't do it * in ocfs2_cluster_disconnect().  The ocfs2_leave_group() function does * the actual work. */void ocfs2_cluster_hangup(const char *group, int grouplen){	BUG_ON(group == NULL);	BUG_ON(group[grouplen] != '\0'); 	ocfs2_leave_group(group); 	/* cluster_disconnect() was called with hangup_pending==1 */	ocfs2_stack_driver_put();}EXPORT_SYMBOL_GPL(ocfs2_cluster_hangup); int ocfs2_cluster_this_node(struct ocfs2_cluster_connection *conn,			    unsigned int *node){	return active_stack->sp_ops->this_node(conn, node);}EXPORT_SYMBOL_GPL(ocfs2_cluster_this_node);  /* * Sysfs bits */ static ssize_t ocfs2_max_locking_protocol_show(struct kobject *kobj,					       struct kobj_attribute *attr,					       char *buf){	ssize_t ret = 0; 	spin_lock(&ocfs2_stack_lock);	if (locking_max_version.pv_major)		ret = snprintf(buf, PAGE_SIZE, "%u.%u\n",			       locking_max_version.pv_major,			       locking_max_version.pv_minor);	spin_unlock(&ocfs2_stack_lock); 	return ret;} static struct kobj_attribute ocfs2_attr_max_locking_protocol =	__ATTR(max_locking_protocol, S_IRUGO,	       ocfs2_max_locking_protocol_show, NULL); static ssize_t ocfs2_loaded_cluster_plugins_show(struct kobject *kobj,						 struct kobj_attribute *attr,						 char *buf){	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;	struct ocfs2_stack_plugin *p; 	spin_lock(&ocfs2_stack_lock);	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {

Lines 1–500 of 701.