ocfs2: fix the end cluster offset of FIEMAP
[linux-3.10.git] / fs / ocfs2 / stackglue.c
index bf45d9b..39abf89 100644 (file)
@@ -6,7 +6,7 @@
  * Code which implements an OCFS2 specific interface to underlying
  * cluster stacks.
  *
- * Copyright (C) 2007 Oracle.  All rights reserved.
+ * Copyright (C) 2007, 2009 Oracle.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
+#include <linux/sysctl.h>
 
 #include "ocfs2_fs.h"
 
 
 #define OCFS2_STACK_PLUGIN_O2CB                "o2cb"
 #define OCFS2_STACK_PLUGIN_USER                "user"
+#define OCFS2_MAX_HB_CTL_PATH          256
 
-static struct ocfs2_locking_protocol *lproto;
+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,
@@ -94,13 +97,14 @@ static int ocfs2_stack_driver_request(const char *stack_name,
                goto out;
        }
 
-       /* Ok, the stack is pinned */
-       p->sp_count++;
        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;
 }
@@ -172,7 +176,7 @@ int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin)
        spin_lock(&ocfs2_stack_lock);
        if (!ocfs2_stack_lookup(plugin->sp_name)) {
                plugin->sp_count = 0;
-               plugin->sp_proto = lproto;
+               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);
@@ -209,77 +213,105 @@ void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin)
 }
 EXPORT_SYMBOL_GPL(ocfs2_stack_glue_unregister);
 
-void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto)
+void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_proto)
 {
        struct ocfs2_stack_plugin *p;
 
-       BUG_ON(proto == NULL);
-
        spin_lock(&ocfs2_stack_lock);
-       BUG_ON(active_stack != NULL);
+       if (memcmp(max_proto, &locking_max_version,
+                  sizeof(struct ocfs2_protocol_version))) {
+               BUG_ON(locking_max_version.pv_major != 0);
 
-       lproto = proto;
-       list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
-               p->sp_proto = lproto;
+               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_locking_protocol);
+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,
-                  union ocfs2_dlm_lksb *lksb,
+                  struct ocfs2_dlm_lksb *lksb,
                   u32 flags,
                   void *name,
-                  unsigned int namelen,
-                  void *astarg)
+                  unsigned int namelen)
 {
-       BUG_ON(lproto == NULL);
-
+       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, astarg);
+                                             name, namelen);
 }
 EXPORT_SYMBOL_GPL(ocfs2_dlm_lock);
 
 int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,
-                    union ocfs2_dlm_lksb *lksb,
-                    u32 flags,
-                    void *astarg)
+                    struct ocfs2_dlm_lksb *lksb,
+                    u32 flags)
 {
-       BUG_ON(lproto == NULL);
+       BUG_ON(lksb->lksb_conn == NULL);
 
-       return active_stack->sp_ops->dlm_unlock(conn, lksb, flags, astarg);
+       return active_stack->sp_ops->dlm_unlock(conn, lksb, flags);
 }
 EXPORT_SYMBOL_GPL(ocfs2_dlm_unlock);
 
-int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb)
+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);
 
-/*
- * Why don't we cast to ocfs2_meta_lvb?  The "clean" answer is that we
- * don't cast at the glue level.  The real answer is that the header
- * ordering is nigh impossible.
- */
-void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb)
+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(union ocfs2_dlm_lksb *lksb)
+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 *group,
                          int grouplen,
+                         struct ocfs2_locking_protocol *lproto,
                          void (*recovery_handler)(int node_num,
                                                   void *recovery_data),
                          void *recovery_data,
@@ -297,6 +329,12 @@ int ocfs2_cluster_connect(const char *stack_name,
                goto out;
        }
 
+       if (memcmp(&lproto->lp_max_version, &locking_max_version,
+                  sizeof(struct ocfs2_protocol_version))) {
+               rc = -EINVAL;
+               goto out;
+       }
+
        new_conn = kzalloc(sizeof(struct ocfs2_cluster_connection),
                           GFP_KERNEL);
        if (!new_conn) {
@@ -309,6 +347,7 @@ int ocfs2_cluster_connect(const char *stack_name,
        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;
 
@@ -334,6 +373,24 @@ out:
 }
 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, 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)
@@ -342,7 +399,7 @@ int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,
 
        BUG_ON(conn == NULL);
 
-       ret = active_stack->sp_ops->disconnect(conn, hangup_pending);
+       ret = active_stack->sp_ops->disconnect(conn);
 
        /* XXX Should we free it anyway? */
        if (!ret) {
@@ -355,12 +412,48 @@ int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,
 }
 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');
 
-       active_stack->sp_ops->hangup(group, grouplen);
+       ocfs2_leave_group(group);
 
        /* cluster_disconnect() was called with hangup_pending==1 */
        ocfs2_stack_driver_put();
@@ -385,10 +478,10 @@ static ssize_t ocfs2_max_locking_protocol_show(struct kobject *kobj,
        ssize_t ret = 0;
 
        spin_lock(&ocfs2_stack_lock);
-       if (lproto)
+       if (locking_max_version.pv_major)
                ret = snprintf(buf, PAGE_SIZE, "%u.%u\n",
-                              lproto->lp_max_version.pv_major,
-                              lproto->lp_max_version.pv_minor);
+                              locking_max_version.pv_major,
+                              locking_max_version.pv_minor);
        spin_unlock(&ocfs2_stack_lock);
 
        return ret;
@@ -540,17 +633,90 @@ error:
        return ret;
 }
 
+/*
+ * Sysctl bits
+ *
+ * The sysctl lives at /proc/sys/fs/ocfs2/nm/hb_ctl_path.  The 'nm' doesn't
+ * make as much sense in a multiple cluster stack world, but it's safer
+ * and easier to preserve the name.
+ */
+
+#define FS_OCFS2_NM            1
+
+static ctl_table ocfs2_nm_table[] = {
+       {
+               .procname       = "hb_ctl_path",
+               .data           = ocfs2_hb_ctl_path,
+               .maxlen         = OCFS2_MAX_HB_CTL_PATH,
+               .mode           = 0644,
+               .proc_handler   = proc_dostring,
+       },
+       { }
+};
+
+static ctl_table ocfs2_mod_table[] = {
+       {
+               .procname       = "nm",
+               .data           = NULL,
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = ocfs2_nm_table
+       },
+       { }
+};
+
+static ctl_table ocfs2_kern_table[] = {
+       {
+               .procname       = "ocfs2",
+               .data           = NULL,
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = ocfs2_mod_table
+       },
+       { }
+};
+
+static ctl_table ocfs2_root_table[] = {
+       {
+               .procname       = "fs",
+               .data           = NULL,
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = ocfs2_kern_table
+       },
+       { }
+};
+
+static struct ctl_table_header *ocfs2_table_header = NULL;
+
+
+/*
+ * Initialization
+ */
+
 static int __init ocfs2_stack_glue_init(void)
 {
        strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
 
+       ocfs2_table_header = register_sysctl_table(ocfs2_root_table);
+       if (!ocfs2_table_header) {
+               printk(KERN_ERR
+                      "ocfs2 stack glue: unable to register sysctl\n");
+               return -ENOMEM; /* or something. */
+       }
+
        return ocfs2_sysfs_init();
 }
 
 static void __exit ocfs2_stack_glue_exit(void)
 {
-       lproto = NULL;
+       memset(&locking_max_version, 0,
+              sizeof(struct ocfs2_protocol_version));
+       locking_max_version.pv_major = 0;
+       locking_max_version.pv_minor = 0;
        ocfs2_sysfs_exit();
+       if (ocfs2_table_header)
+               unregister_sysctl_table(ocfs2_table_header);
 }
 
 MODULE_AUTHOR("Oracle");