[Ocfs2-tools-commits] jlbec commits r1374 -
branches/cman-based/ocfs2_controld
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Wed Aug 8 13:45:04 PDT 2007
Author: jlbec
Date: 2007-08-08 13:45:02 -0700 (Wed, 08 Aug 2007)
New Revision: 1374
Added:
branches/cman-based/ocfs2_controld/action.c
branches/cman-based/ocfs2_controld/client_proto.c
branches/cman-based/ocfs2_controld/ocfs2_controld.h
Modified:
branches/cman-based/ocfs2_controld/Makefile
branches/cman-based/ocfs2_controld/group.c
branches/cman-based/ocfs2_controld/main.c
branches/cman-based/ocfs2_controld/member_cman.c
branches/cman-based/ocfs2_controld/ocfs2_controld_internal.h
Log:
We do a lot of things. The state machine for mount groups is much different,
we've reworked the client protocol. Etc. I'm really just commiting to save
the work.
Modified: branches/cman-based/ocfs2_controld/Makefile
===================================================================
--- branches/cman-based/ocfs2_controld/Makefile 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/Makefile 2007-08-08 20:45:02 UTC (rev 1374)
@@ -26,7 +26,7 @@
DEFINES = -DO2CB_FLAT_INCLUDES -DVERSION=\"$(VERSION)\"
-CFILES = group.c main.c member_cman.c
+CFILES = group.c main.c member_cman.c client_proto.c action.c
HFILES = ocfs2_controld.h
Added: branches/cman-based/ocfs2_controld/action.c
===================================================================
--- branches/cman-based/ocfs2_controld/action.c 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/action.c 2007-08-08 20:45:02 UTC (rev 1374)
@@ -0,0 +1,911 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+/* Portions of this file are: */
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "o2cb.h"
+#include "ocfs2_controld.h"
+#include "ocfs2_controld_internal.h"
+
+
+enum mountgroup_state {
+ MG_CREATED = 1 << 0,
+ MG_JOIN_SENT = 1 << 1,
+ MG_JOIN_START = 1 << 2,
+ MG_JOIN_START_DONE = 1 << 3,
+#define MG_JOINING (MG_JOIN_SENT | MG_JOIN_START | MG_JOIN_START_DONE)
+ MG_JOINED = 1 << 4,
+ MG_MOUNTED = 1 << 5,
+#define MG_MEMBER (MG_JOINED | MG_MOUNTED)
+ MG_LEAVE_SENT = 1 << 6,
+ MG_LEAVE_START = 1 << 7,
+ MG_LEAVE_START_DONE = 1 << 8,
+#define MG_LEAVING (MG_LEAVE_SENT | MG_LEAVE_START | MG_LEAVE_START_DONE)
+ MG_DEAD = 1 << 9,
+};
+
+struct list_head mounts;
+
+static void fill_error(struct mountgroup *mg, int error, char *errfmt, ...)
+{
+ int rc;
+ va_list args;
+
+ if (mg->error)
+ return;
+
+ mg->error = error;
+
+ va_start(args, errfmt);
+ rc = vsnprintf(mg->error_msg, sizeof(mg->error_msg), errfmt, args);
+ va_end(args);
+
+ if (rc >= sizeof(mg->error_msg)) {
+ log_debug("Error message truncated");
+ mg->error_msg[sizeof(mg->error_msg) - 1] = '\0';
+ }
+}
+
+static int mg_statep(struct mountgroup *mg, enum mountgroup_state test,
+ enum mountgroup_state allowed)
+{
+ if (mg->state == test)
+ return 1;
+
+ if (allowed) {
+ if (!(mg->state & allowed))
+ log_error("mountgroup %s is in state %d, testing for %d, allowed %d",
+ mg->uuid, mg->state, test, allowed);
+ }
+
+ return 0;
+}
+
+static int mg_joining(struct mountgroup *mg)
+{
+ return mg_statep(mg, MG_JOINING, 0);
+}
+
+static int mg_leaving(struct mountgroup *mg)
+{
+ return mg_statep(mg, MG_LEAVING, 0);
+}
+
+static void notify_mount_client(struct mountgroup *mg)
+{
+ int error = mg->error;
+ char *error_msg = "OK";
+
+ if (error) {
+ if (mg->error_msg[0]) {
+ error_msg = mg->error_msg;
+ } else
+ error_msg = strerror(-error);
+ mg->error = 0;
+ }
+
+ log_group(mg, "notify_mount_client sending %d \"%s\"", -error,
+ error_msg);
+
+ error = send_message(mg->mount_client_fd, CM_STATUS, error,
+ error_msg);
+ if (error)
+ log_error("Unable to notify client, send_message failed with %d: %s",
+ -error, strerror(-error));
+ else
+ mg->mount_client_notified = 1;
+
+ /*
+ * XXX If we failed to notify the client, what can we do? I'm
+ * guessing that our main loop will get POLLHUP of some sort.
+ */
+}
+
+static int create_mountpoint(struct mountgroup *mg, const char *mountpoint,
+ int ci)
+{
+ int rc = -ENOMEM;
+ struct mountpoint *mp;
+
+ mp = malloc(sizeof(struct mountpoint));
+ if (mp) {
+ memset(mp, 0, sizeof(struct mountpoint));
+ strncpy(mp->mountpoint, mountpoint, sizeof(mp->mountpoint));
+ mp->client = ci;
+ list_add(&mp->list, &mg->mountpoints);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static struct mountpoint *find_mountpoint(struct mountgroup *mg,
+ const char *mountpoint, int ci)
+{
+ struct mountpoint *mp;
+ struct list_head *p;
+ int found = 0;
+
+ list_for_each(p, &mg->mountpoints) {
+ mp = list_entry(p, struct mountpoint, list);
+ if (ci && (mp->client != ci))
+ continue;
+ if (!strcmp(mp->mountpoint, mountpoint)) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? mp : NULL;
+}
+
+static void remove_failed_mountpoint(struct mountgroup *mg,
+ const char *mountpoint, int ci)
+{
+ struct mountpoint *mp;
+
+ mp = find_mountpoint(mg, mountpoint, ci);
+ if (mp) {
+ list_del(&mp->list);
+ free(mp);
+ }
+
+ assert(mp);
+}
+
+static void add_another_mountpoint(struct mountgroup *mg,
+ const char *mountpoint,
+ const char *device, int ci)
+{
+ log_group(mg, "add_another_mountpoint %s device %s ci %d",
+ mountpoint, device, ci);
+
+ if (strcmp(mg->device, device)) {
+ fill_error(mg, -EINVAL,
+ "Trying to mount fs %s on device %s, but it already is mounted from device %s",
+ mg->uuid, mg->device, device);
+ goto out;
+ }
+
+ if (find_mountpoint(mg, mountpoint, 0)) {
+ fill_error(mg, -EBUSY,
+ "Filesystem %s is already mounted on %s",
+ mg->uuid, mountpoint);
+ goto out;
+ }
+
+ if (mg->mount_client || mg->mount_client_fd || !mg->kernel_mount_done) {
+ fill_error(mg, -EBUSY, "Another mount is in process");
+ goto out;
+ }
+
+ if (create_mountpoint(mg, mountpoint, ci)) {
+ fill_error(mg, -ENOMEM,
+ "Unable to allocate mountpoint structure");
+ goto out;
+ }
+
+ mg->mount_client = ci;
+
+ /*
+ * This special error is returned to mount.ocfs2 to tell it that
+ * the mount is a secondary one and no additional work is required.
+ * It will just call mount(2).
+ */
+ fill_error(mg, -EALREADY, "Kernel mounted, go ahead");
+
+out:
+ return;
+}
+
+struct mountgroup *find_mg(const char *uuid)
+{
+ struct list_head *p;
+ struct mountgroup *mg;
+
+ list_for_each(p, &mounts) {
+ mg = list_entry(p, struct mountgroup, list);
+ if ((strlen(mg->uuid) == strlen(uuid)) &&
+ !strncmp(mg->uuid, uuid, strlen(uuid)))
+ return mg;
+ }
+ return NULL;
+}
+
+static struct mountgroup *create_mg(const char *uuid, const char *mountpoint,
+ int ci)
+{
+ struct mountgroup *mg = NULL;
+
+ mg = malloc(sizeof(struct mountgroup));
+ if (!mg)
+ goto out;
+
+ memset(mg, 0, sizeof(struct mountgroup));
+ INIT_LIST_HEAD(&mg->members);
+ INIT_LIST_HEAD(&mg->mountpoints);
+ mg->state = MG_CREATED;
+ strncpy(mg->uuid, uuid, sizeof(mg->uuid));
+
+ if (create_mountpoint(mg, mountpoint, ci)) {
+ free(mg);
+ mg = NULL;
+ }
+
+out:
+ return mg;
+}
+
+int do_mount(int ci, int fd, const char *fstype, const char *uuid,
+ const char *cluster, const char *device,
+ const char *mountpoint, struct mountgroup **mg_ret)
+{
+ int rc = 0;
+ struct mountgroup mg_error = { /* Until we have a real one */
+ .error = 0,
+ };
+ struct mountgroup *mg = &mg_error;
+
+ log_debug("mount: MOUNT %s %s %s %s %s",
+ fstype, uuid, cluster, device, mountpoint);
+
+ if (strcmp(fstype, "ocfs2")) {
+ fill_error(mg, -EINVAL, "Unsupported fstype: %s", fstype);
+ goto out;
+ }
+
+ if (!strlen(cluster) || (strlen(cluster) != strlen(clustername)) ||
+ strcmp(cluster, clustername)) {
+ fill_error(mg, -EINVAL,
+ "Request for mount in cluster %s but we belong to %s",
+ cluster, clustername);
+ goto out;
+ }
+
+ if (strlen(uuid) > MAXNAME) {
+ fill_error(mg, -ENAMETOOLONG, "UUID too long: %s", uuid);
+ goto out;
+ }
+
+ mg = find_mg(uuid);
+ if (mg) {
+ add_another_mountpoint(mg, mountpoint, device, ci);
+ goto out;
+ }
+
+ /* Here we stop using &mg_error and start using our real one */
+ mg = create_mg(uuid, mountpoint, ci);
+ if (!mg) {
+ mg = &mg_error; /* Well, almost */
+ fill_error(mg, -ENOMEM,
+ "Unable to allocate mountgroup structure");
+ goto out;
+ }
+
+ mg->mount_client = ci;
+ strncpy(mg->type, fstype, sizeof(mg->type));
+ strncpy(mg->cluster, cluster, sizeof(mg->cluster));
+ strncpy(mg->device, device, sizeof(mg->device));
+ list_add(&mg->list, &mounts);
+
+ rc = group_join(gh, (char *)uuid);
+ if (rc) {
+ fill_error(mg, -errno, "Unable to start group join: %s",
+ strerror(errno));
+
+ /*
+ * Remove the mountpoint so we can free the mountgroup
+ * at the bottom.
+ */
+ remove_failed_mountpoint(mg, mountpoint, ci);
+ goto out;
+ }
+
+ mg->state = MG_JOIN_SENT;
+
+ *mg_ret = mg;
+ log_group(mg, "mount successfully started");
+
+out:
+ /*
+ * Only reply on error. If we're doing OK, the reply is delayed
+ * until join completes (notify_mount_client()).
+ */
+ if (mg->error) {
+ rc = mg->error;
+ send_message(fd, CM_STATUS, mg->error, mg->error_msg);
+
+ /* -EALREADY magic is sent, clear it */
+ if (mg->error == -EALREADY)
+ mg->error = 0;
+ else {
+ log_error("mount: %s", mg->error_msg);
+
+ if ((mg != &mg_error) &&
+ list_empty(&mg->mountpoints)) {
+ log_debug("mount: freeing failed mountgroup");
+ list_del(&mg->list);
+ free(mg);
+ }
+ }
+ }
+
+ log_debug("do_mount returns %d", rc);
+ return rc;
+}
+
+int do_mount_result(struct mountgroup *mg, int ci, int another,
+ const char *fstype, const char *uuid,
+ const char *errcode, const char *mountpoint)
+{
+ int rc = 0;
+ int reply = 1;
+ char *ptr = NULL;
+ long err;
+
+ log_debug("mount: MRESULT %s %s %s %s",
+ fstype, uuid, errcode, mountpoint);
+
+ assert(mg->mount_client == ci);
+ assert(!mg->error);
+
+ if (strcmp(fstype, "ocfs2")) {
+ fill_error(mg, -EINVAL, "Unsupported fstype: %s", fstype);
+ goto out;
+ }
+
+ if (strlen(uuid) > MAXNAME) {
+ fill_error(mg, -ENAMETOOLONG, "UUID too long: %s", uuid);
+ goto out;
+ }
+
+ if (strcmp(uuid, mg->uuid)) {
+ fill_error(mg, -EINVAL,
+ "UUID %s does not match mountgroup %s", uuid,
+ mg->uuid);
+ goto out;
+ }
+
+ /* XXX Check that mountpoint is valid */
+
+ err = strtol(errcode, &ptr, 10);
+ if (ptr && *ptr != '\0') {
+ fill_error(mg, -EINVAL, "Invalid error code string: %s",
+ errcode);
+ goto out;
+ }
+ if ((err == LONG_MIN) || (err == LONG_MAX) || (err < INT_MIN) ||
+ (err > INT_MAX)) {
+ fill_error(mg, -ERANGE, "Error code %ld out of range", err);
+ goto out;
+ }
+
+ if (another) {
+ if (err) {
+ remove_failed_mountpoint(mg, mountpoint, ci);
+ assert(!list_empty(&mg->mountpoints));
+ }
+ /*
+ * rc is zero, we're responding to mount.ocfs2 that we
+ * got the message. There's nothing else to do.
+ */
+ goto out;
+ }
+
+ mg->kernel_mount_done = 1;
+ mg->kernel_mount_error = err;
+
+ if (!err) {
+ /* Everyone's happy */
+ mg->mount_client = 0;
+ mg->mount_client_fd = 0;
+
+ goto out;
+ }
+
+ /*
+ * We're failing an initial mount. We keep mount_client_fd around
+ * both to send the result of the LEAVE as well as to keep other
+ * clients from trying to race us. We don't reply to the client
+ * until the LEAVE has completed.
+ */
+ reply = 0;
+ remove_failed_mountpoint(mg, mountpoint, ci);
+ assert(list_empty(&mg->mountpoints));
+
+ /* We shouldn't get to MRESULT unless we're a member, but... */
+ if (!mg_statep(mg, MG_MEMBER, MG_MEMBER)) {
+ mg->group_leave_on_finish = 1;
+ goto out;
+ }
+
+ if (group_leave(gh, mg->uuid))
+ fill_error(mg, -errno, "Unable to start group leave: %s",
+ strerror(errno));
+ else
+ mg->state = MG_LEAVE_SENT;
+
+out:
+ if (reply)
+ send_message(mg->mount_client_fd, CM_STATUS, mg->error,
+ mg->error ? mg->error_msg : "OK");
+
+ return rc;
+}
+
+int do_unmount(int ci, int fd, const char *fstype, const char *uuid,
+ const char *mountpoint)
+{
+ int rc = 0;
+ int reply = 1;
+ struct mountgroup mg_error = {
+ .error = 0,
+ };
+ struct mountgroup *mg;
+ struct mountpoint *mp;
+
+ log_debug("unmount: UMOUNT %s %s %s",
+ fstype, uuid, mountpoint);
+
+ if (strcmp(fstype, "ocfs2")) {
+ fill_error(&mg_error, -EINVAL, "Unsupported fstype: %s",
+ fstype);
+ goto out;
+ }
+
+ if (strlen(uuid) > MAXNAME) {
+ fill_error(&mg_error, -ENAMETOOLONG, "UUID too long: %s",
+ uuid);
+ goto out;
+ }
+
+ /* Once we have our mg, we're done with &mg_error */
+ mg = find_mg(uuid);
+ if (!mg) {
+ fill_error(&mg_error, -ENOENT, "Unknown uuid %s", uuid);
+ goto out;
+ }
+
+ /* We shouldn't find the mg if the uuid isn't mounted *somewhere* */
+ assert(!list_empty(&mg->mountpoints));
+
+ mp = find_mountpoint(mg, mountpoint, 0);
+ if (!mp) {
+ fill_error(&mg_error, -ENOENT,
+ "Filesystem %s is not mounted on %s", uuid,
+ mountpoint);
+ goto out;
+ }
+
+ /* XXX Do we check kernel_mount_done? */
+
+ log_group(mg, "removing mountpoint %s", mountpoint);
+ list_del(&mp->list);
+ free(mp);
+
+ if (!list_empty(&mg->mountpoints)) {
+ log_group(mg, "mounts still remain");
+ goto out;
+ }
+
+ /*
+ * We're clearing the last mount. We must leave the group before
+ * we let umount.ocfs2 complete. Thus, we'll let
+ * notify_mount_client() handle the rest.
+ */
+
+ reply = 0;
+
+ /*
+ * We shouldn't be allowing another client to connect before
+ * we get to MG_MEMBER, but let's be safe
+ */
+ if (!mg_statep(mg, MG_MEMBER, MG_MEMBER)) {
+ mg->group_leave_on_finish = 1;
+ goto out;
+ }
+
+ if (group_leave(gh, mg->uuid)) {
+ /* We spoke too soon! */
+ /* XXX How can a client clean this up? */
+ reply = 1;
+ fill_error(&mg_error, -errno, "Unable to leave group: %s",
+ strerror(errno));
+ } else
+ mg->state = MG_LEAVE_SENT;
+
+out:
+ if (reply)
+ send_message(fd, CM_STATUS, mg_error.error,
+ mg_error.error ? mg_error.error_msg : "OK");
+
+ return rc;
+}
+
+static struct mg_member *find_memb_nodeid(struct mountgroup *mg, int nodeid)
+{
+ struct list_head *p;
+ struct mg_member *memb;
+
+ list_for_each(p, &mg->members) {
+ memb = list_entry(p, struct mg_member, list);
+ if (memb->nodeid == nodeid)
+ return memb;
+ }
+ return NULL;
+}
+
+#define MEMBER_LINK_FORMAT "/sys/kernel/config/cluster/%s/region/%s/%s"
+#define MEMBER_TARGET_FORMAT "/sys/kernel/config/cluster/%s/node/%s"
+static int drop_member(struct mountgroup *mg, struct mg_member *memb)
+{
+ int rc;
+ char link[PATH_MAX+1];
+
+ /*
+ * XXX Can we just remove here, or should we wait until
+ * do_finish()? I think we can just remove them
+ */
+
+ list_del(&memb->list);
+ memb->gone_event = mg->start_event_nr;
+ memb->gone_type = mg->start_type;
+ mg->memb_count--;
+
+ snprintf(link, PATH_MAX, MEMBER_LINK_FORMAT, clustername, mg->uuid,
+ memb->name);
+ rc = rmdir(link);
+ if (rc)
+ log_error("rmdir of %s failed: %d", link, errno);
+
+ free(memb);
+
+ return rc;
+}
+
+static int add_member(struct mountgroup *mg, int nodeid)
+{
+ int rc;
+ struct list_head *p;
+ char *node_name;
+ struct mg_member *memb, *test, *target = NULL;
+ char link[PATH_MAX+1], nodepath[PATH_MAX+1];
+
+ memb = malloc(sizeof(struct mg_member));
+ if (!memb) {
+ rc = -errno;
+ goto out;
+ }
+
+ memset(memb, 0, sizeof(struct mg_member));
+ memb->nodeid = nodeid;
+ node_name = nodeid2name(nodeid);
+ if (!node_name) {
+ log_error("Unable to determine name for node %d", nodeid);
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ strncpy(memb->name, node_name, NAME_MAX);
+ mg->memb_count++;
+
+ list_for_each(p, &mg->members) {
+ test = list_entry(p, struct mg_member, list);
+ if (memb->nodeid < test->nodeid) {
+ target = test;
+ break;
+ }
+ }
+
+ snprintf(link, PATH_MAX, MEMBER_LINK_FORMAT, clustername, mg->uuid,
+ memb->name);
+ snprintf(nodepath, PATH_MAX, MEMBER_TARGET_FORMAT, clustername,
+ memb->name);
+
+ rc = symlink(nodepath, link);
+ if (rc) {
+ rc = -errno;
+ goto out_free;
+ }
+
+ if (target)
+ list_add_tail(&memb->list, &target->list);
+ else
+ list_add_tail(&memb->list, &mg->members);
+
+out_free:
+ if (rc)
+ free(memb);
+
+out:
+ return rc;
+}
+
+static int is_member(struct mountgroup *mg, int nodeid)
+{
+ return find_memb_nodeid(mg, nodeid) != NULL;
+}
+
+static int path_exists(const char *path)
+{
+ struct stat buf;
+
+ if (stat(path, &buf) < 0) {
+ if (errno != ENOENT)
+ log_error("%s: stat failed: %d", path, errno);
+ return 0;
+ }
+ return 1;
+}
+
+static int create_path(char *path)
+{
+ mode_t old_umask;
+ int rv;
+
+ old_umask = umask(0022);
+ rv = mkdir(path, 0777);
+ umask(old_umask);
+
+ if (rv < 0) {
+ rv = -errno;
+ log_error("%s: mkdir failed: %d", path, -rv);
+ if (-rv == EEXIST)
+ rv = 0;
+ }
+ return rv;
+}
+
+#define REGION_FORMAT "/sys/kernel/config/cluster/%s/heartbeat/%s"
+static int initialize_region(struct mountgroup *mg)
+{
+ int rc = 0;
+ char path[PATH_MAX+1];
+
+ snprintf(path, PATH_MAX, REGION_FORMAT, clustername, mg->uuid);
+
+ if (!path_exists(path)) {
+ rc = create_path(path);
+ if (rc) {
+ fill_error(mg, -rc, "Unable to create region %s",
+ mg->uuid);
+ mg->group_leave_on_finish = 1;
+ }
+ }
+
+ return rc;
+}
+
+static int drop_region(struct mountgroup *mg)
+{
+ int rc = 0;
+ char path[PATH_MAX+1];
+
+ snprintf(path, PATH_MAX, REGION_FORMAT, clustername, mg->uuid);
+
+ if (path_exists(path)) {
+ rc = rmdir(path);
+ if (rc) {
+ rc = -errno;
+ fill_error(mg, -rc, "Unable to remove region %s",
+ mg->uuid);
+ }
+ }
+
+ return rc;
+}
+
+static void down_members(struct mountgroup *mg, int member_count,
+ int *nodeids)
+{
+ int found, rc, i;
+ struct list_head *p, *t;
+ struct mg_member *memb;
+
+ list_for_each_safe(p, t, &mg->members) {
+ memb = list_entry(p, struct mg_member, list);
+ found = 0;
+ for (i = 0; i < member_count; i++) {
+ if (memb->nodeid == nodeids[i]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ if (mg->start_type == GROUP_NODE_JOIN) {
+ log_error("down_members: Somehow we got a member gone (%d) during a JOIN!",
+ memb->nodeid);
+ /* Continue anyway, it's gone */
+ }
+
+ rc = drop_member(mg, memb);
+ /*
+ * I don't think we care that drop_member failed, even
+ * during join. Yes, we probably don't like that ocfs2
+ * won't get a notification if drop_member() failed, but
+ * there's nothing we can do. Let's just ignore rc.
+ */
+ }
+}
+
+static void up_members(struct mountgroup *mg, int member_count,
+ int *nodeids)
+{
+ int i, rc;
+
+ for (i = 0; i < member_count; i++) {
+ if (is_member(mg, nodeids[i]))
+ continue;
+
+ if (mg->start_type == GROUP_NODE_LEAVE) {
+ log_error("up_members: Somehow we got at member added (%d) during a LEAVE!",
+ nodeids[i]);
+ /* Continue anyway */
+ }
+
+ if ((nodeids[i] == our_nodeid) &&
+ (!mg_statep(mg, MG_JOIN_START,
+ MG_MEMBER | MG_LEAVE_START)))
+ log_error("up_members: we got ourselves up in a join event we didn't expect! Group is %s ",
+ mg->uuid);
+
+ rc = add_member(mg, nodeids[i]);
+ if (rc && mg_joining(mg)) {
+ fill_error(mg, -rc, "Unable to join group %s",
+ mg->uuid);
+ mg->group_leave_on_finish = 1;
+ }
+ }
+}
+
+void do_stop(struct mountgroup *mg)
+{
+ /*
+ * As far as I can tell, we don't have to do anything here. Later
+ * we might want to freeze ocfs2, but currently it handles its own
+ * thang.
+ */
+ log_group(mg, "do_stop() called");
+
+ group_stop_done(gh, mg->uuid);
+}
+
+/*
+ * The ocfs2 membership scheme makes this pretty simple. We can just
+ * go ahead and modify the group in o2cb. After all members have called
+ * start_done, the mounting node's do_finish() can notify mount.ocfs2.
+ */
+void do_start(struct mountgroup *mg, int type, int member_count,
+ int *nodeids)
+{
+ if (mg_statep(mg, MG_JOIN_SENT, MG_MEMBER | MG_LEAVE_SENT))
+ mg->state = MG_JOIN_START;
+ else if (mg_statep(mg, MG_LEAVE_SENT, MG_MEMBER | MG_JOIN_SENT))
+ mg->state = MG_LEAVE_START;
+
+ mg->start_event_nr = mg->last_start;
+ mg->start_type = type;
+
+ log_group(mg,
+ "start %d state %d type %d member_count %d",
+ mg->last_start, mg->state, type,
+ member_count);
+
+ if (mg_joining(mg)) {
+ if (initialize_region(mg))
+ goto out;
+ }
+
+ down_members(mg, member_count, nodeids);
+ up_members(mg, member_count, nodeids);
+
+out:
+ group_start_done(gh, mg->uuid, mg->start_event_nr);
+ if (mg_statep(mg, MG_JOIN_START, MG_MEMBER | MG_LEAVE_START))
+ mg->state = MG_JOIN_START_DONE;
+ else if (mg_statep(mg, MG_LEAVE_START, MG_MEMBER | MG_JOIN_START))
+ mg->state = MG_LEAVE_START_DONE;
+}
+
+void do_finish(struct mountgroup *mg)
+{
+ log_group(mg, "finish called");
+
+ if (mg_statep(mg, MG_JOIN_START_DONE, MG_MEMBER)) {
+ mg->state = MG_JOINED;
+ if (!mg->error) {
+ assert(!mg->group_leave_on_finish);
+ notify_mount_client(mg);
+ } else {
+ /*
+ * We had a problem joining the group. We're going
+ * to leave it, and we don't want to notify
+ * mount.ocfs2 until we've done that. It will
+ * happen in do_terminate().
+ */
+ assert(mg->group_leave_on_finish);
+ }
+ }
+
+ /*
+ * We do this when we determine it's time to leave but we're
+ * processing another node's join/leave events. Here we know they
+ * are done, so we can call leave.
+ *
+ * We trust that if a node is both (MG_MEMBER && ->leave_on_finish),
+ * the notify_mount_client() above will have sent mount.ocfs2 an
+ * error.
+ */
+ if (mg_statep(mg, MG_MEMBER, MG_MEMBER) &&
+ mg->group_leave_on_finish) {
+ log_group(mg, "leaving group after delay for join to finish");
+ if (group_leave(gh, mg->uuid))
+ log_error("group_leave(%s) failed: %s",
+ mg->uuid, strerror(errno));
+ else
+ mg->state = MG_LEAVE_SENT;
+ mg->group_leave_on_finish = 0;
+ }
+}
+
+void do_terminate(struct mountgroup *mg)
+{
+ log_group(mg, "termination of our unmount leave");
+
+ if (!mg_statep(mg, MG_LEAVE_START_DONE, MG_LEAVE_START_DONE))
+ log_error("terminate called from state %d for group %s",
+ mg->state, mg->uuid);
+
+ mg->state = MG_DEAD;
+
+ if (mg->mount_client)
+ notify_mount_client(mg);
+
+ /*
+ * A successful mount means that do_unmount() must have cleared
+ * the mountpoint. A failed mount means that do_mount_result()
+ * cleared the mountpoint. Either way, the list of mountpoints
+ * had better be empty by the time we've left the group.
+ */
+ assert(list_empty(&mg->mountpoints));
+
+ /*
+ * Drop all members from our local region, as we don't care about
+ * them anymore.
+ */
+ down_members(mg, 0, NULL);
+ assert(list_empty(&mg->members));
+
+ if (drop_region(mg))
+ log_error("Error removing region %s", mg->uuid);
+
+ list_del(&mg->list);
+ free(mg);
+}
Added: branches/cman-based/ocfs2_controld/client_proto.c
===================================================================
--- branches/cman-based/ocfs2_controld/client_proto.c 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/client_proto.c 2007-08-08 20:45:02 UTC (rev 1374)
@@ -0,0 +1,255 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ocfs2_controld.h"
+
+struct client_message {
+ char *cm_command;
+ int cm_argcount;
+ char *cm_format;
+};
+
+#define BEGIN_MESSAGES(_list) struct client_message _list[] = {
+#define END_MESSAGES(_list) }; \
+ int _list##_len = sizeof(_list) / sizeof(_list[0]);
+#define DEFINE_MESSAGE(_name, _argcount, _format) [CM_##_name] = { \
+ .cm_command = #_name, \
+ .cm_argcount = _argcount, \
+ .cm_format = #_name " " _format, \
+},
+
+BEGIN_MESSAGES(message_list)
+DEFINE_MESSAGE(MOUNT, 5, "%s %s %s %s %s")
+DEFINE_MESSAGE(MRESULT, 4, "%s %s %d %s")
+DEFINE_MESSAGE(UNMOUNT, 3, "%s %s %s")
+DEFINE_MESSAGE(STATUS, 2, "%d %s")
+END_MESSAGES(message_list)
+
+/* No short reads allowed */
+static int full_read(int fd, void *buf, size_t count)
+{
+ size_t off = 0;
+ ssize_t rc = 0;
+
+ while (off < count) {
+ rc = read(fd, buf + off, count - off);
+ if (rc == 0)
+ return -EPIPE;
+ if (rc == -1) {
+ rc = -errno;
+ if (rc == -EINTR)
+ continue;
+ break;
+ }
+ off += rc;
+ rc = 0;
+ }
+ return rc;
+}
+
+/* No short writes allowed */
+static int full_write(int fd, void *buf, size_t count)
+{
+ size_t off = 0;
+ ssize_t rc = 0;
+
+ while (off < count) {
+ rc = write(fd, buf + off, count - off);
+ if (rc == 0)
+ return -EPIPE;
+ if (rc == -1) {
+ rc = -errno;
+ if (rc == -EINTR)
+ continue;
+ break;
+ }
+ off += rc;
+ rc = 0;
+ }
+ return rc;
+}
+
+int send_message(int fd, client_message message, ...)
+{
+ int rc;
+ va_list args;
+ char mbuf[OCFS2_CONTROLD_MAXLINE];
+
+ va_start(args, message);
+ rc = vsnprintf(mbuf, OCFS2_CONTROLD_MAXLINE,
+ message_list[message].cm_format, args);
+ va_end(args);
+ if (rc >= OCFS2_CONTROLD_MAXLINE)
+ rc = -E2BIG;
+ else
+ rc = full_write(fd, mbuf, OCFS2_CONTROLD_MAXLINE);
+
+ return rc;
+}
+
+static char *get_args(char *buf, int *argc, char **argv, char sep, int want)
+{
+ char *p = buf, *rp = NULL;
+ int i = 0;
+
+ /* Skip the first word, which is the command */
+ p = strchr(buf, sep);
+ if (!p)
+ goto out;
+ p += 1;
+ argv[0] = p;
+
+ for (i = 1; i < OCFS2_CONTROLD_MAXARGS; i++) {
+ p = strchr(p, sep);
+ if (!p) {
+ rp = p + 1;
+ break;
+ }
+
+ if (want == i)
+ break;
+
+ *p = '\0';
+ p += 1;
+ argv[i] = p;
+ }
+
+out:
+ if (argc)
+ *argc = i;
+
+ /* Terminate the list, the caller expects us to */
+ argv[i] = NULL;
+
+ /* we ended by hitting \0, return the point following that */
+ if (!rp)
+ rp = strchr(buf, '\0') + 1;
+
+ return rp;
+}
+
+int receive_message_full(int fd, client_message *message, char **argv,
+ char **rest)
+{
+ int i, rc, len, count;
+ client_message msg;
+ char *r;
+ char mbuf[OCFS2_CONTROLD_MAXLINE];
+
+ rc = full_read(fd, mbuf, OCFS2_CONTROLD_MAXLINE);
+ if (rc)
+ goto out;
+
+ /* Safety first */
+ mbuf[OCFS2_CONTROLD_MAXLINE - 1] = '\0';
+
+
+ for (i = 0; i < message_list_len; i++) {
+ len = strlen(message_list[i].cm_command);
+ if (!strncmp(mbuf, message_list[i].cm_command, len) &&
+ (mbuf[len] == ' '))
+ break;
+ }
+ if (i >= message_list_len) {
+ rc = -EBADMSG;
+ goto out;
+ }
+ msg = i;
+
+ r = get_args(mbuf, &count, argv, ' ',
+ message_list[msg].cm_argcount);
+ if (count != message_list[msg].cm_argcount) {
+ rc = -EBADMSG;
+ } else {
+ if (message)
+ *message = msg;
+ if (rest)
+ *rest = r;
+ }
+
+out:
+ return rc;
+}
+
+int receive_message(int fd, client_message *message, char **argv)
+{
+ return receive_message_full(fd, message, argv, NULL);
+}
+
+int client_listen(void)
+{
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int rv, s;
+
+ /* we listen for new client connections on socket s */
+
+ s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (s < 0) {
+ /* log_error("socket error %d %d", s, errno); */
+ return s;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ strcpy(&addr.sun_path[1], OCFS2_CONTROLD_SOCK_PATH);
+ addrlen = sizeof(sa_family_t) + strlen(addr.sun_path+1) + 1;
+
+ rv = bind(s, (struct sockaddr *) &addr, addrlen);
+ if (rv < 0) {
+ /* log_error("bind error %d %d", rv, errno); */
+ close(s);
+ return rv;
+ }
+
+ rv = listen(s, 5);
+ if (rv < 0) {
+ /* log_error("listen error %d %d", rv, errno); */
+ close(s);
+ return rv;
+ }
+
+ /* log_debug("listen %d", s); */
+
+ return s;
+}
+
+int client_connect(void)
+{
+ struct sockaddr_un sun;
+ socklen_t addrlen;
+ int rv, fd;
+
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ goto out;
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strcpy(&sun.sun_path[1], OCFS2_CONTROLD_SOCK_PATH);
+ addrlen = sizeof(sa_family_t) + strlen(sun.sun_path+1) + 1;
+
+ rv = connect(fd, (struct sockaddr *) &sun, addrlen);
+ if (rv < 0) {
+ close(fd);
+ fd = rv;
+ }
+ out:
+ return fd;
+}
Modified: branches/cman-based/ocfs2_controld/group.c
===================================================================
--- branches/cman-based/ocfs2_controld/group.c 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/group.c 2007-08-08 20:45:02 UTC (rev 1374)
@@ -22,7 +22,6 @@
* of the GNU General Public License v.2.
*/
-//#include "ocfs2_controld.h"
#include "ocfs2_controld_internal.h"
#define OCFS2_CONTROLD_GROUP_NAME "ocfs2"
@@ -44,12 +43,7 @@
static int cb_member_count;
static int cb_members[MAX_GROUP_MEMBERS];
-int do_stop(struct mountgroup *mg);
-int do_finish(struct mountgroup *mg);
-int do_terminate(struct mountgroup *mg);
-int do_start(struct mountgroup *mg, int type, int count, int *nodeids);
-
static void stop_cbfn(group_handle_t h, void *private, char *name)
{
cb_action = DO_STOP;
@@ -109,12 +103,13 @@
static char *str_members(void)
{
- static char buf[MAXLINE];
+#define LINESIZE 1024
+ static char buf[LINESIZE];
int i, len = 0;
- memset(buf, 0, MAXLINE);
+ memset(buf, 0, LINESIZE);
- for (i = 0; i < cb_member_count; i++)
+ for (i = 0; (i < cb_member_count) && (len < LINESIZE); i++)
len += sprintf(buf+len, "%d ", cb_members[i]);
return buf;
}
Modified: branches/cman-based/ocfs2_controld/main.c
===================================================================
--- branches/cman-based/ocfs2_controld/main.c 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/main.c 2007-08-08 20:45:02 UTC (rev 1374)
@@ -22,11 +22,11 @@
* of the GNU General Public License v.2.
*/
-//#include "ocfs2_controld.h"
+#include "ocfs2_controld.h"
#include "ocfs2_controld_internal.h"
-#define OPTION_STRING "DPhVwpl:"
-#define LOCKFILE_NAME "/var/run/gfs_controld.pid"
+#define OPTION_STRING "DhVw"
+#define LOCKFILE_NAME "/var/run/ocfs2_controld.pid"
#define DEFAULT_PLOCK_RATE_LIMIT 100
@@ -88,56 +88,7 @@
return 0;
}
-#if 0
-static void make_args(char *buf, int *argc, char **argv, char sep)
-{
- char *p = buf;
- int i;
- argv[0] = p;
-
- for (i = 1; i < MAXARGS; i++) {
- p = strchr(buf, sep);
- if (!p)
- break;
- *p = '\0';
- argv[i] = p + 1;
- buf = p + 1;
- }
- *argc = i;
-}
-#endif
-
-static char *get_args(char *buf, int *argc, char **argv, char sep, int want)
-{
- char *p = buf, *rp = NULL;
- int i;
-
- argv[0] = p;
-
- for (i = 1; i < MAXARGS; i++) {
- p = strchr(buf, sep);
- if (!p)
- break;
- *p = '\0';
-
- if (want == i) {
- rp = p + 1;
- break;
- }
-
- argv[i] = p + 1;
- buf = p + 1;
- }
- *argc = i;
-
- /* we ended by hitting \0, return the point following that */
- if (!rp)
- rp = strchr(buf, '\0') + 1;
-
- return rp;
-}
-
static int client_add(int fd)
{
int i;
@@ -186,11 +137,6 @@
client[ci].mg = NULL;
}
-int client_send(int ci, char *buf, int len)
-{
- return do_write(client[ci].fd, buf, len);
-}
-
static int dump_debug(int ci)
{
int len = DUMP_SIZE;
@@ -260,45 +206,63 @@
static int process_client(int ci)
{
struct mountgroup *mg;
- char buf[MAXLINE], *argv[MAXARGS], out[MAXLINE];
- char *cmd = NULL;
- int argc = 0, rv, fd;
+ client_message message;
+ char out[OCFS2_CONTROLD_MAXLINE];
+ char *argv[OCFS2_CONTROLD_MAXARGS + 1];
+ int rv, fd = client[ci].fd;
- memset(buf, 0, MAXLINE);
- memset(out, 0, MAXLINE);
- memset(argv, 0, sizeof(char *) * MAXARGS);
+ memset(out, 0, OCFS2_CONTROLD_MAXLINE);
- rv = read(client[ci].fd, buf, MAXLINE);
- if (!rv) {
+ /* receive_message ensures we have the proper number of arguments */
+ rv = receive_message(fd, &message, argv);
+ if (rv == -EPIPE) {
client_dead(ci);
return 0;
}
if (rv < 0) {
- log_debug("client %d fd %d read error %d %d", ci,
- client[ci].fd, rv, errno);
+ /* XXX: Should print better errors matching our returns */
+ log_debug("client %d fd %d read error %d", ci, fd, -rv);
return rv;
}
- log_debug("client %d: %s", ci, buf);
+ log_debug("client message %d: %d", ci, message);
- get_args(buf, &argc, argv, ' ', 7);
- cmd = argv[0];
- rv = 0;
-
- if (!strcmp(cmd, "join")) {
- /* ci, dir (mountpoint), type (gfs/gfs2), proto (lock_dlm),
- table (fsname:clustername), extra (rw), dev (/dev/sda1) */
-
- rv = do_mount(ci, argv[1], argv[2], argv[3], argv[4], argv[5],
- argv[6], &mg);
- fd = client[ci].fd;
+ switch (message) {
+ case CM_MOUNT:
+ rv = do_mount(ci, fd, argv[0], argv[1], argv[2], argv[3],
+ argv[4], &mg);
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if (!rv || rv == -EALREADY) {
client[ci].another_mount = rv;
client[ci].mg = mg;
mg->mount_client_fd = fd;
}
- goto reply;
+ break;
+
+ case CM_MRESULT:
+ rv = do_mount_result(client[ci].mg, ci,
+ client[ci].another_mount,
+ argv[0], argv[1], argv[2], argv[3]);
+ break;
+
+ case CM_UNMOUNT:
+ rv = do_unmount(ci, fd, argv[0], argv[1], argv[2]);
+ if (!rv) {
+ client[ci].mg = mg;
+ mg->mount_client_fd = fd;
+ }
+ break;
+
+ case CM_STATUS:
+ log_error("Someone sent us cm_status!");
+ break;
+
+ default:
+ log_error("Invalid message received");
+ break;
+ }
+
+#if 0
} else if (!strcmp(cmd, "mount_result")) {
got_mount_result(client[ci].mg, atoi(argv[3]), ci,
client[ci].another_mount);
@@ -317,58 +281,16 @@
rv = -EINVAL;
goto reply;
}
+#endif
return rv;
-
- reply:
- sprintf(out, "%d", rv);
- rv = client_send(ci, out, MAXLINE);
- return rv;
}
-static int setup_listen(void)
-{
- struct sockaddr_un addr;
- socklen_t addrlen;
- int rv, s;
-
- /* we listen for new client connections on socket s */
-
- s = socket(AF_LOCAL, SOCK_STREAM, 0);
- if (s < 0) {
- log_error("socket error %d %d", s, errno);
- return s;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
- strcpy(&addr.sun_path[1], OCFS2_CONTROLD_SOCK_PATH);
- addrlen = sizeof(sa_family_t) + strlen(addr.sun_path+1) + 1;
-
- rv = bind(s, (struct sockaddr *) &addr, addrlen);
- if (rv < 0) {
- log_error("bind error %d %d", rv, errno);
- close(s);
- return rv;
- }
-
- rv = listen(s, 5);
- if (rv < 0) {
- log_error("listen error %d %d", rv, errno);
- close(s);
- return rv;
- }
-
- log_debug("listen %d", s);
-
- return s;
-}
-
static int loop(void)
{
int rv, i, f, poll_timeout = -1;
- rv = listen_fd = setup_listen();
+ rv = listen_fd = client_listen();
if (rv < 0)
goto out;
client_add(listen_fd);
@@ -587,7 +509,7 @@
{
prog_name = argv[0];
INIT_LIST_HEAD(&mounts);
- INIT_LIST_HEAD(&withdrawn_mounts);
+ /* INIT_LIST_HEAD(&withdrawn_mounts); */
decode_arguments(argc, argv);
Modified: branches/cman-based/ocfs2_controld/member_cman.c
===================================================================
--- branches/cman-based/ocfs2_controld/member_cman.c 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/member_cman.c 2007-08-08 20:45:02 UTC (rev 1374)
@@ -32,7 +32,7 @@
#include <arpa/inet.h>
#include <libcman.h>
-//#include "ocfs2_controld.h"
+#include "o2cb.h"
#include "ocfs2_controld_internal.h"
int our_nodeid;
@@ -40,20 +40,108 @@
cman_cluster_t cluster;
static cman_handle_t ch;
extern struct list_head mounts;
+static cman_node_t old_nodes[O2NM_MAX_NODES];
+static int old_node_count;
+static cman_node_t cman_nodes[O2NM_MAX_NODES];
+static int cman_node_count;
-static void cman_callback(cman_handle_t h, void *private, int reason, int arg)
+static int is_member(cman_node_t *node_list, int count, int nodeid)
{
- if (reason == CMAN_REASON_TRY_SHUTDOWN) {
- if (list_empty(&mounts))
- cman_replyto_shutdown(ch, 1);
- else {
- log_debug("no to cman shutdown");
- cman_replyto_shutdown(ch, 0);
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (node_list[i].cn_nodeid == nodeid)
+ return node_list[i].cn_member;
+ }
+ return 0;
+}
+
+static int is_old_member(int nodeid)
+{
+ return is_member(old_nodes, old_node_count, nodeid);
+}
+
+static int is_cman_member(int nodeid)
+{
+ return is_member(cman_nodes, cman_node_count, nodeid);
+}
+
+static cman_node_t *find_cman_node(int nodeid)
+{
+ int i;
+
+ for (i = 0; i < cman_node_count; i++) {
+ if (cman_nodes[i].cn_nodeid == nodeid)
+ return &cman_nodes[i];
+ }
+ return NULL;
+}
+
+char *nodeid2name(int nodeid)
+{
+ cman_node_t *cn;
+
+ cn = find_cman_node(nodeid);
+ if (!cn)
+ return NULL;
+ return cn->cn_name;
+}
+
+/* keep track of the nodes */
+static void statechange(void)
+{
+ int i, rv;
+
+ old_node_count = cman_node_count;
+ memcpy(&old_nodes, &cman_nodes, sizeof(old_nodes));
+
+ cman_node_count = 0;
+ memset(&cman_nodes, 0, sizeof(cman_nodes));
+ rv = cman_get_nodes(ch, O2NM_MAX_NODES, &cman_node_count,
+ cman_nodes);
+ if (rv < 0) {
+ log_debug("cman_get_nodes error %d %d", rv, errno);
+ return;
+ }
+
+ for (i = 0; i < old_node_count; i++) {
+ if (old_nodes[i].cn_member &&
+ !is_cman_member(old_nodes[i].cn_nodeid)) {
+
+ log_debug("cman: node %d removed",
+ old_nodes[i].cn_nodeid);
}
}
+
+ for (i = 0; i < cman_node_count; i++) {
+ if (cman_nodes[i].cn_member &&
+ !is_old_member(cman_nodes[i].cn_nodeid)) {
+
+ log_debug("cman: node %d added",
+ cman_nodes[i].cn_nodeid);
+ }
+ }
}
+static void cman_callback(cman_handle_t h, void *private, int reason, int arg)
+{
+ switch (reason) {
+ case CMAN_REASON_TRY_SHUTDOWN:
+ if (list_empty(&mounts))
+ cman_replyto_shutdown(ch, 1);
+ else {
+ log_debug("no to cman shutdown");
+ cman_replyto_shutdown(ch, 0);
+ }
+ break;
+
+ case CMAN_REASON_STATECHANGE:
+ statechange();
+ break;
+ }
+}
+
void exit_cman(void)
{
log_error("cluster is down, exiting");
@@ -108,6 +196,15 @@
our_nodeid = node.cn_nodeid;
fd = cman_get_fd(ch);
+
+ old_node_count = 0;
+ memset(&old_nodes, 0, sizeof(old_nodes));
+ cman_node_count = 0;
+ memset(&cman_nodes, 0, sizeof(cman_nodes));
+
+ /* Fill the node list */
+ statechange();
+
return fd;
fail_stop:
Added: branches/cman-based/ocfs2_controld/ocfs2_controld.h
===================================================================
--- branches/cman-based/ocfs2_controld/ocfs2_controld.h 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/ocfs2_controld.h 2007-08-08 20:45:02 UTC (rev 1374)
@@ -0,0 +1,48 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ */
+
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __OCFS2_CONTROLD_H
+#define __OCFS2_CONTROLD_H
+
+/* Basic communication properties */
+#define OCFS2_CONTROLD_MAXLINE 256
+#define OCFS2_CONTROLD_MAXARGS 16
+#define OCFS2_CONTROLD_SOCK_PATH "ocfs2_controld_sock"
+
+/* Client messages */
+typedef enum {
+ CM_MOUNT,
+ CM_MRESULT,
+ CM_UNMOUNT,
+ CM_STATUS,
+} client_message;
+
+int client_listen(void);
+int client_connect(void);
+int send_message(int fd, client_message message, ...);
+int receive_message(int fd, client_message *message, char **argv);
+int receive_message_full(int fd, client_message *message, char **argv,
+ char **rest);
+
+#endif
Modified: branches/cman-based/ocfs2_controld/ocfs2_controld_internal.h
===================================================================
--- branches/cman-based/ocfs2_controld/ocfs2_controld_internal.h 2007-07-25 07:26:25 UTC (rev 1373)
+++ branches/cman-based/ocfs2_controld/ocfs2_controld_internal.h 2007-08-08 20:45:02 UTC (rev 1374)
@@ -22,8 +22,8 @@
* of the GNU General Public License v.2.
*/
-#ifndef __OCFS2_CONTROLD_H
-#define __OCFS2_CONTROLD_H
+#ifndef __OCFS2_CONTROLD_INTERNAL_H
+#define __OCFS2_CONTROLD_INTERNAL_H
#include <unistd.h>
#include <stdio.h>
@@ -39,13 +39,13 @@
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
-#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <linux/netlink.h>
+#include <sys/un.h>
#include "kernel-list.h"
#include "libgroup.h"
@@ -76,6 +76,9 @@
};
extern char *prog_name;
+extern char *clustername;
+extern int our_nodeid;
+extern group_handle_t gh;
extern int daemon_debug_opt;
extern char daemon_debug_buf[256];
extern char dump_buf[DUMP_SIZE];
@@ -94,18 +97,11 @@
#define log_group(g, fmt, args...) \
do { \
snprintf(daemon_debug_buf, 255, "%ld %s " fmt "\n", time(NULL), \
- (g)->name, ##args); \
+ (g)->uuid, ##args); \
if (daemon_debug_opt) fprintf(stderr, "%s", daemon_debug_buf); \
daemon_dump_save(); \
} while (0)
-#define log_plock(g, fmt, args...) \
-do { \
- snprintf(daemon_debug_buf, 255, "%ld %s " fmt "\n", time(NULL), \
- (g)->name, ##args); \
- if (plock_debug_opt) fprintf(stderr, "%s", daemon_debug_buf); \
-} while (0)
-
#define log_error(fmt, args...) \
do { \
log_debug(fmt, ##args); \
@@ -123,7 +119,7 @@
struct mountpoint {
struct list_head list;
- char dir[PATH_MAX+1];
+ char mountpoint[PATH_MAX+1];
int client;
};
@@ -131,16 +127,14 @@
struct list_head list;
uint32_t id;
struct list_head members;
- struct list_head members_gone;
int memb_count;
- struct list_head resources; /* for plocks */
struct list_head mountpoints;
- char name[MAXNAME+1];
- char table[MAXNAME+1];
+ char uuid[MAXNAME+1];
+ char cluster[MAXNAME+1];
char type[5];
char options[MAX_OPTIONS_LEN+1];
- char dev[PATH_MAX+1];
+ char device[PATH_MAX+1];
int last_stop;
int last_start;
@@ -149,6 +143,7 @@
int start_event_nr;
int start_type;
+ int error;
char error_msg[128];
int mount_client;
int mount_client_fd;
@@ -156,7 +151,7 @@
int mount_client_delay;
int group_leave_on_finish;
int remount_client;
- int init;
+ int state;
int got_our_options;
int got_our_journals;
int delay_send_journals;
@@ -168,7 +163,6 @@
int readonly;
int rw;
- struct list_head saved_messages;
void *start2_fn;
};
@@ -200,6 +194,7 @@
struct mg_member {
struct list_head list;
int nodeid;
+ char name[NAME_MAX+1];
int spectator;
int readonly;
@@ -228,21 +223,31 @@
int do_read(int fd, void *buf, size_t count);
int do_write(int fd, void *buf, size_t count);
-struct mountgroup *find_mg(char *name);
+struct mountgroup *find_mg(const char *uuid);
struct mountgroup *find_mg_id(uint32_t id);
+void do_stop(struct mountgroup *mg);
+void do_start(struct mountgroup *mg, int type, int member_count,
+ int *nodeids);
+void do_finish(struct mountgroup *mg);
+void do_terminate(struct mountgroup *mg);
int setup_cman(void);
int process_cman(void);
+char *nodeid2name(int nodeid);
int setup_groupd(void);
int process_groupd(void);
void exit_cman(void);
-int do_mount(int ci, char *dir, char *type, char *proto, char *table,
- char *options, char *dev, struct mountgroup **mg_ret);
-int do_unmount(int ci, char *dir, int mnterr);
+int do_mount(int ci, int fd, const char *fstype, const char *uuid,
+ const char *cluster, const char *device,
+ const char *mountpoint, struct mountgroup **mg_ret);
+int do_mount_result(struct mountgroup *mg, int ci, int another,
+ const char *fstype, const char *uuid,
+ const char *errcode, const char *mountpoint);
+int do_unmount(int ci, int fd, const char *fstype, const char *uuid,
+ const char *mountpoint);
int do_remount(int ci, char *dir, char *mode);
void ping_kernel_mount(char *table);
-void got_mount_result(struct mountgroup *mg, int result, int ci, int another);
int client_send(int ci, char *buf, int len);
More information about the Ocfs2-tools-commits
mailing list