[Ocfs2-tools-commits] jlbec commits r1368 - in branches/cman-based: . o2cb_controld ocfs2_controld

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Tue Jul 17 17:21:29 PDT 2007


Author: jlbec
Date: 2007-07-17 17:21:27 -0700 (Tue, 17 Jul 2007)
New Revision: 1368

Added:
   branches/cman-based/ocfs2_controld/
   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.h
Modified:
   branches/cman-based/Makefile
   branches/cman-based/o2cb_controld/member_cman.c
Log:

Add the ocfs2_controld skeleton.  It doesn't compile, but I want the
original code in source control so we can compare it later.




Modified: branches/cman-based/Makefile
===================================================================
--- branches/cman-based/Makefile	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/Makefile	2007-07-18 00:21:27 UTC (rev 1368)
@@ -31,7 +31,7 @@
 endif
 
 ifdef BUILD_CMAN_SUPPORT
-SUBDIRS += o2cb_controld
+SUBDIRS += o2cb_controld # ocfs2_controld
 endif
 
 SUBDIRS += vendor

Modified: branches/cman-based/o2cb_controld/member_cman.c
===================================================================
--- branches/cman-based/o2cb_controld/member_cman.c	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/o2cb_controld/member_cman.c	2007-07-18 00:21:27 UTC (rev 1368)
@@ -145,7 +145,7 @@
 {
 	switch (reason) {
 	case CMAN_REASON_TRY_SHUTDOWN:
-		/* XXX we need to check heartbeat here */
+		/* XXX do we need to check heartbeat here */
 #if 0
 		if (list_empty(&lockspaces))
 #endif

Added: branches/cman-based/ocfs2_controld/Makefile
===================================================================
--- branches/cman-based/ocfs2_controld/Makefile	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/ocfs2_controld/Makefile	2007-07-18 00:21:27 UTC (rev 1368)
@@ -0,0 +1,42 @@
+TOPDIR = ..
+
+include $(TOPDIR)/Preamble.make
+
+SBIN_PROGRAMS = ocfs2_controld
+
+#INCLUDES = -Iinclude -I$(TOPDIR)/libocfs2/include \
+#	    -I$(TOPDIR)/libo2cb/include -I$(TOPDIR)/libo2dlm/include
+#LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
+#LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
+#LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm
+#LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a
+
+INCLUDES = -I$(TOPDIR)/libo2dlm/include -I$(TOPDIR)/libo2cb/include
+LIBO2CB_LIBS = -L$(TOPDIR)/libo2cb -lo2cb
+LIBO2CB_DEPS = $(TOPDIR)/libo2cb/libo2cb.a
+
+ifdef OCFS2_DEBUG
+OPTS += -ggdb
+else
+OPTS += -O2
+endif
+
+CFLAGS := $(OPTS) -Wall -Wstrict-prototypes -Wmissing-prototypes \
+           -Wmissing-declarations
+
+DEFINES = -DO2CB_FLAT_INCLUDES -DVERSION=\"$(VERSION)\"
+
+CFILES = main.c member_cman.c group.c
+
+
+HFILES = ocfs2_controld.h
+
+OBJS = $(subst .c,.o,$(CFILES))
+#MANS = ocfs2_dlm_controld
+
+DIST_FILES = $(CFILES) $(HFILES) $(addsuffix .in,$(MANS))
+
+o2cb_controld: $(OBJS) $(LIBO2CB_DEPS)
+	$(LINK) $(LIBO2CB_LIBS) $(COM_ERR_LIBS) -lcman
+
+include $(TOPDIR)/Postamble.make

Added: branches/cman-based/ocfs2_controld/group.c
===================================================================
--- branches/cman-based/ocfs2_controld/group.c	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/ocfs2_controld/group.c	2007-07-18 00:21:27 UTC (rev 1368)
@@ -0,0 +1,204 @@
+/* -*- 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.
+ */
+
+#include "ocfs2_controld.h"
+
+#define OCFS2_CONTROLD_GROUP_NAME "ocfs2"
+#define OCFS2_CONTROLD_GROUP_LEVEL 2  /* Because gfs_controld uses 2.
+					 I think all that matters is that
+					 we are a higher number than
+					 fenced, which uses 0. */
+
+
+/* save all the params from callback functions here because we can't
+   do the processing within the callback function itself */
+
+group_handle_t gh;
+static int cb_action;
+static char cb_name[MAX_GROUP_NAME_LEN+1];
+static int cb_event_nr;
+static unsigned int cb_id;
+static int cb_type;
+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;
+	strcpy(cb_name, name);
+}
+
+static void start_cbfn(group_handle_t h, void *private, char *name,
+		       int event_nr, int type, int member_count, int *members)
+{
+	int i;
+
+	cb_action = DO_START;
+	strncpy(cb_name, name, MAX_GROUP_NAME_LEN);
+	cb_event_nr = event_nr;
+	cb_type = type;
+	cb_member_count = member_count;
+
+	for (i = 0; i < member_count; i++)
+		cb_members[i] = members[i];
+}
+
+static void finish_cbfn(group_handle_t h, void *private, char *name,
+			int event_nr)
+{
+	cb_action = DO_FINISH;
+	strncpy(cb_name, name, MAX_GROUP_NAME_LEN);
+	cb_event_nr = event_nr;
+}
+
+static void terminate_cbfn(group_handle_t h, void *private, char *name)
+{
+	cb_action = DO_TERMINATE;
+	strncpy(cb_name, name, MAX_GROUP_NAME_LEN);
+}
+
+static void setid_cbfn(group_handle_t h, void *private, char *name,
+		       unsigned int id)
+{
+	cb_action = DO_SETID;
+	strncpy(cb_name, name, MAX_GROUP_NAME_LEN);
+	cb_id = id;
+}
+
+static void deliver_cbfn(group_handle_t h, void *private, char *name,
+			 int nodeid, int len, char *buf)
+{
+}
+
+static group_callbacks_t callbacks = {
+	stop_cbfn,
+	start_cbfn,
+	finish_cbfn,
+	terminate_cbfn,
+	setid_cbfn,
+	deliver_cbfn
+};
+
+char *str_members(void)
+{
+	static char buf[MAXLINE];
+	int i, len = 0;
+
+	memset(buf, 0, MAXLINE);
+
+	for (i = 0; i < cb_member_count; i++)
+		len += sprintf(buf+len, "%d ", cb_members[i]);
+	return buf;
+}
+
+int process_groupd(void)
+{
+	struct mountgroup *mg;
+	int error = 0;
+
+	error = group_dispatch(gh);
+	if (error) {
+		log_error("groupd_dispatch error %d errno %d", error, errno);
+		goto out;
+	}
+
+	if (!cb_action)
+		goto out;
+
+	mg = find_mg(cb_name);
+	if (!mg) {
+		log_error("callback %d group %s not found", cb_action, cb_name);
+		error = -1;
+		goto out;
+	}
+
+	switch (cb_action) {
+	case DO_STOP:
+		log_debug("groupd cb: stop %s", cb_name);
+		mg->last_callback = DO_STOP;
+		mg->last_stop = mg->last_start;
+		do_stop(mg);
+		break;
+
+	case DO_START:
+		log_debug("groupd cb: start %s type %d count %d members %s",
+			  cb_name, cb_type, cb_member_count, str_members());
+		mg->last_callback = DO_START;
+		mg->last_start = cb_event_nr;
+		do_start(mg, cb_type, cb_member_count, cb_members);
+		break;
+
+	case DO_FINISH:
+		log_debug("groupd cb: finish %s", cb_name);
+		mg->last_callback = DO_FINISH;
+		mg->last_finish = cb_event_nr;
+		do_finish(mg);
+		break;
+
+	case DO_TERMINATE:
+		log_debug("groupd cb: terminate %s", cb_name);
+		mg->last_callback = DO_TERMINATE;
+		do_terminate(mg);
+		break;
+
+	case DO_SETID:
+		log_debug("groupd cb: set_id %s %x", cb_name, cb_id);
+		mg->id = cb_id;
+		break;
+
+	default:
+		error = -EINVAL;
+	}
+
+ out:
+	cb_action = 0;
+	return error;
+}
+
+int setup_groupd(void)
+{
+	int rv;
+
+	gh = group_init(NULL, OCFS2_CONTROLD_GROUP_NAME,
+			OCFS2_CONTROLD_GROUP_LEVEL, &callbacks, 10);
+	if (!gh) {
+		log_error("group_init error %d %d", (int) gh, errno);
+		return -ENOTCONN;
+	}
+
+	rv = group_get_fd(gh);
+	if (rv < 0)
+		log_error("group_get_fd error %d %d", rv, errno);
+
+	log_debug("groupd %d", rv);
+
+	return rv;
+}
+

Added: branches/cman-based/ocfs2_controld/main.c
===================================================================
--- branches/cman-based/ocfs2_controld/main.c	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/ocfs2_controld/main.c	2007-07-18 00:21:27 UTC (rev 1368)
@@ -0,0 +1,780 @@
+/* -*- 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.
+ */
+
+#include "ocfs2_controld.h"
+
+#define OPTION_STRING			"DPhVwpl:"
+#define LOCKFILE_NAME			"/var/run/gfs_controld.pid"
+
+#define DEFAULT_PLOCK_RATE_LIMIT 100
+
+struct client {
+	int fd;
+	char type[32];
+	struct mountgroup *mg;
+	int another_mount;
+};
+
+static int client_maxi;
+static int client_size = 0;
+static struct client *client = NULL;
+static struct pollfd *pollfd = NULL;
+
+static int cman_fd;
+static int cpg_fd;
+static int listen_fd;
+static int groupd_fd;
+static int uevent_fd;
+static int plocks_fd;
+static int plocks_ci;
+
+extern struct list_head mounts;
+extern struct list_head withdrawn_mounts;
+int no_withdraw;
+int no_plock;
+uint32_t plock_rate_limit = DEFAULT_PLOCK_RATE_LIMIT;
+int dmsetup_wait;
+
+int do_read(int fd, void *buf, size_t count)
+{
+	int rv, off = 0;
+
+	while (off < count) {
+		rv = read(fd, buf + off, count - off);
+		if (rv == 0)
+			return -1;
+		if (rv == -1 && errno == EINTR)
+			continue;
+		if (rv == -1)
+			return -1;
+		off += rv;
+	}
+	return 0;
+}
+
+int do_write(int fd, void *buf, size_t count)
+{
+	int rv, off = 0;
+
+ retry:
+	rv = write(fd, buf + off, count);
+	if (rv == -1 && errno == EINTR)
+		goto retry;
+	if (rv < 0) {
+		log_error("write errno %d", errno);
+		return rv;
+	}
+
+	if (rv != count) {
+		count -= rv;
+		off += rv;
+		goto retry;
+	}
+	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;
+
+	while (1) {
+		/* This fails the first time with client_size of zero */
+		for (i = 0; i < client_size; i++) {
+			if (client[i].fd == -1) {
+				client[i].fd = fd;
+				pollfd[i].fd = fd;
+				pollfd[i].events = POLLIN;
+				if (i > client_maxi)
+					client_maxi = i;
+				return i;
+			}
+		}
+
+		/* We didn't find an empty slot, so allocate more. */
+		client_size += MAX_CLIENTS;
+
+		if (!client) {
+			client = malloc(client_size * sizeof(struct client));
+			pollfd = malloc(client_size * sizeof(struct pollfd));
+		} else {
+			client = realloc(client, client_size *
+						 sizeof(struct client));
+			pollfd = realloc(pollfd, client_size *
+						 sizeof(struct pollfd));
+		}
+		if (!client || !pollfd)
+			log_error("Can't allocate client memory.");
+
+		for (i = client_size - MAX_CLIENTS; i < client_size; i++) {
+			client[i].fd = -1;
+			pollfd[i].fd = -1;
+		}
+	}
+}
+
+static void client_dead(int ci)
+{
+	log_debug("client %d fd %d dead", ci, client[ci].fd);
+	close(client[ci].fd);
+	client[ci].fd = -1;
+	pollfd[ci].fd = -1;
+	client[ci].mg = NULL;
+}
+
+static void client_ignore(int ci, int fd)
+{
+	pollfd[ci].fd = -1;
+	pollfd[ci].events = 0;
+}
+
+static void client_back(int ci, int fd)
+{
+	pollfd[ci].fd = fd;
+	pollfd[ci].events = POLLIN;
+}
+
+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;
+
+	if (dump_wrap) {
+		len = DUMP_SIZE - dump_point;
+		do_write(client[ci].fd, dump_buf + dump_point, len);
+		len = dump_point;
+	}
+
+	do_write(client[ci].fd, dump_buf, len);
+	return 0;
+}
+
+#if 0
+/* mount.gfs sends us a special fd that it will write an error message to
+   if mount(2) fails.  We can monitor this fd for an error message while
+   waiting for the kernel mount outside our main poll loop */
+
+void setup_mount_error_fd(struct mountgroup *mg)
+{
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct iovec vec;
+	char tmp[CMSG_SPACE(sizeof(int))];
+	int fd, socket = client[mg->mount_client].fd;
+	char ch;
+	ssize_t n;
+
+	memset(&msg, 0, sizeof(msg));
+
+	vec.iov_base = &ch;
+	vec.iov_len = 1;
+	msg.msg_iov = &vec;
+	msg.msg_iovlen = 1;
+	msg.msg_control = tmp;
+	msg.msg_controllen = sizeof(tmp);
+
+	n = recvmsg(socket, &msg, 0);
+	if (n < 0) {
+		log_group(mg, "setup_mount_error_fd recvmsg err %d errno %d",
+			  n, errno);
+		return;
+	}
+	if (n != 1) {
+		log_group(mg, "setup_mount_error_fd recvmsg got %ld", (long)n);
+		return;
+	}
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+
+	if (cmsg->cmsg_type != SCM_RIGHTS) {
+		log_group(mg, "setup_mount_error_fd expected type %d got %d",
+			  SCM_RIGHTS, cmsg->cmsg_type);
+		return;
+	}
+
+	fd = (*(int *)CMSG_DATA(cmsg));
+	mg->mount_error_fd = fd;
+
+	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+	log_group(mg, "setup_mount_error_fd got fd %d", fd);
+}
+#endif
+
+static int process_client(int ci)
+{
+	struct mountgroup *mg;
+	char buf[MAXLINE], *argv[MAXARGS], out[MAXLINE];
+	char *cmd = NULL;
+	int argc = 0, rv, fd;
+
+	memset(buf, 0, MAXLINE);
+	memset(out, 0, MAXLINE);
+	memset(argv, 0, sizeof(char *) * MAXARGS);
+
+	rv = read(client[ci].fd, buf, MAXLINE);
+	if (!rv) {
+		client_dead(ci);
+		return 0;
+	}
+	if (rv < 0) {
+		log_debug("client %d fd %d read error %d %d", ci,
+			   client[ci].fd, rv, errno);
+		return rv;
+	}
+
+	log_debug("client %d: %s", ci, buf);
+
+	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;
+		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;
+	} else if (!strcmp(cmd, "mount_result")) {
+		got_mount_result(client[ci].mg, atoi(argv[3]), ci,
+				 client[ci].another_mount);
+	} else if (!strcmp(cmd, "leave")) {
+		rv = do_unmount(ci, argv[1], atoi(argv[3]));
+		goto reply;
+
+	} else if (!strcmp(cmd, "remount")) {
+		rv = do_remount(ci, argv[1], argv[3]);
+		goto reply;
+
+	} else if (!strcmp(cmd, "dump")) {
+		dump_debug(ci);
+
+	} else if (!strcmp(cmd, "plocks")) {
+		dump_plocks(argv[1], client[ci].fd);
+		client_dead(ci);
+
+	} else {
+		rv = -EINVAL;
+		goto reply;
+	}
+
+	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;
+}
+
+int process_uevent(void)
+{
+	char buf[MAXLINE];
+	char *argv[MAXARGS], *act;
+	int rv, argc = 0;
+
+	memset(buf, 0, sizeof(buf));
+	memset(argv, 0, sizeof(char *) * MAXARGS);
+
+	rv = recv(uevent_fd, &buf, sizeof(buf), 0);
+	if (rv < 0) {
+		log_error("uevent recv error %d errno %d", rv, errno);
+		return -1;
+	}
+
+	if (!strstr(buf, "gfs") || !strstr(buf, "lock_module"))
+		return 0;
+
+	get_args(buf, &argc, argv, '/', 4);
+	if (argc != 4)
+		log_error("uevent message has %d args", argc);
+	act = argv[0];
+
+	log_debug("kernel: %s %s", act, argv[3]);
+
+	if (!strcmp(act, "change@"))
+		kernel_recovery_done(argv[3]);
+	else if (!strcmp(act, "offline@"))
+		do_withdraw(argv[3]);
+	else
+		ping_kernel_mount(argv[3]);
+
+	return 0;
+}
+
+int setup_uevent(void)
+{
+	struct sockaddr_nl snl;
+	int s, rv;
+
+	s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+	if (s < 0) {
+		log_error("netlink socket error %d errno %d", s, errno);
+		return s;
+	}
+
+	memset(&snl, 0, sizeof(snl));
+	snl.nl_family = AF_NETLINK;
+	snl.nl_pid = getpid();
+	snl.nl_groups = 1;
+
+	rv = bind(s, (struct sockaddr *) &snl, sizeof(snl));
+	if (rv < 0) {
+		log_error("uevent bind error %d errno %d", rv, errno);
+		close(s);
+		return rv;
+	}
+
+	log_debug("uevent %d", s);
+
+	return s;
+}
+
+int loop(void)
+{
+	int rv, i, f, error, poll_timeout = -1, ignore_plocks_fd = 0;
+
+	rv = listen_fd = setup_listen();
+	if (rv < 0)
+		goto out;
+	client_add(listen_fd);
+
+	rv = cman_fd = setup_cman();
+	if (rv < 0)
+		goto out;
+	client_add(cman_fd);
+
+	rv = cpg_fd = setup_cpg();
+	if (rv < 0)
+		goto out;
+	client_add(cpg_fd);
+
+	rv = groupd_fd = setup_groupd();
+	if (rv < 0)
+		goto out;
+	client_add(groupd_fd);
+
+	rv = uevent_fd = setup_uevent();
+	if (rv < 0)
+		goto out;
+	client_add(uevent_fd);
+
+	rv = plocks_fd = setup_plocks();
+	if (rv < 0)
+		goto out;
+	plocks_ci = client_add(plocks_fd);
+
+	log_debug("setup done");
+
+	for (;;) {
+		rv = poll(pollfd, client_maxi + 1, poll_timeout);
+		if (rv < 0)
+			log_error("poll error %d errno %d", rv, errno);
+
+		/* client[0] is listening for new connections */
+
+		if (pollfd[0].revents & POLLIN) {
+			f = accept(client[0].fd, NULL, NULL);
+			if (f < 0)
+				log_debug("accept error %d %d", f, errno);
+			else
+				client_add(f);
+		}
+
+		for (i = 1; i <= client_maxi; i++) {
+			if (client[i].fd < 0)
+				continue;
+
+			if (pollfd[i].revents & POLLIN) {
+				if (pollfd[i].fd == groupd_fd)
+					process_groupd();
+				else if (pollfd[i].fd == cman_fd)
+					process_cman();
+				else if (pollfd[i].fd == cpg_fd)
+					process_cpg();
+				else if (pollfd[i].fd == uevent_fd)
+					process_uevent();
+				else if (pollfd[i].fd == plocks_fd) {
+					error = process_plocks();
+					if (error == -EBUSY) {
+						client_ignore(plocks_ci,
+							      plocks_fd);
+						ignore_plocks_fd = 1;
+						poll_timeout = 100;
+					}
+				} else
+					process_client(i);
+			}
+
+			if (pollfd[i].revents & POLLHUP) {
+				if (pollfd[i].fd == cman_fd) {
+					log_error("cman connection died");
+					exit_cman();
+				} else if (pollfd[i].fd == groupd_fd) {
+					log_error("groupd connection died");
+					exit_cman();
+				} else if (pollfd[i].fd == cpg_fd) {
+					log_error("cpg connection died");
+					exit_cman();
+				}
+				client_dead(i);
+			}
+
+			/* check if our plock rate limit has expired so we
+			   can start taking more local plock requests again */
+
+			if (ignore_plocks_fd) {
+				error = process_plocks();
+				if (error != -EBUSY) {
+					client_back(plocks_ci, plocks_fd);
+					ignore_plocks_fd = 0;
+					poll_timeout = -1;
+				}
+			}
+
+			if (dmsetup_wait) {
+				update_dmsetup_wait();
+				if (dmsetup_wait) {
+					if (poll_timeout == -1)
+						poll_timeout = 1000;
+				} else {
+					if (poll_timeout == 1000)
+						poll_timeout = -1;
+				}
+			}
+		}
+	}
+	rv = 0;
+ out:
+	return rv;
+}
+
+static void lockfile(void)
+{
+	int fd, error;
+	struct flock lock;
+	char buf[33];
+
+	memset(buf, 0, 33);
+
+	fd = open(LOCKFILE_NAME, O_CREAT|O_WRONLY,
+		  S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+	if (fd < 0) {
+		fprintf(stderr, "cannot open/create lock file %s\n",
+			LOCKFILE_NAME);
+		exit(EXIT_FAILURE);
+	}
+
+	lock.l_type = F_WRLCK;
+	lock.l_start = 0;
+	lock.l_whence = SEEK_SET;
+	lock.l_len = 0;
+
+	error = fcntl(fd, F_SETLK, &lock);
+	if (error) {
+		fprintf(stderr, "gfs_controld is already running\n");
+		exit(EXIT_FAILURE);
+	}
+
+	error = ftruncate(fd, 0);
+	if (error) {
+		fprintf(stderr, "cannot clear lock file %s\n", LOCKFILE_NAME);
+		exit(EXIT_FAILURE);
+	}
+
+	sprintf(buf, "%d\n", getpid());
+
+	error = write(fd, buf, strlen(buf));
+	if (error <= 0) {
+		fprintf(stderr, "cannot write lock file %s\n", LOCKFILE_NAME);
+		exit(EXIT_FAILURE);
+	}
+}
+
+void daemonize(void)
+{
+	pid_t pid = fork();
+	if (pid < 0) {
+		perror("main: cannot fork");
+		exit(EXIT_FAILURE);
+	}
+	if (pid)
+		exit(EXIT_SUCCESS);
+	setsid();
+	chdir("/");
+	umask(0);
+	close(0);
+	close(1);
+	close(2);
+	openlog("gfs_controld", LOG_PID, LOG_DAEMON);
+
+	lockfile();
+}
+
+static void print_usage(void)
+{
+	printf("Usage:\n");
+	printf("\n");
+	printf("%s [options]\n", prog_name);
+	printf("\n");
+	printf("Options:\n");
+	printf("\n");
+	printf("  -D	       Enable debugging code and don't fork\n");
+	printf("  -P	       Enable plock debugging\n");
+	printf("  -p	       Disable plocks\n");
+	printf("  -l <limit>   Limit the rate of plock operations\n");
+	printf("	       Default is %d, set to 0 for no limit\n", DEFAULT_PLOCK_RATE_LIMIT);
+	printf("  -w	       Disable withdraw\n");
+	printf("  -h	       Print this help, then exit\n");
+	printf("  -V	       Print program version information, then exit\n");
+}
+
+static void decode_arguments(int argc, char **argv)
+{
+	int cont = 1;
+	int optchar;
+
+	while (cont) {
+		optchar = getopt(argc, argv, OPTION_STRING);
+
+		switch (optchar) {
+
+		case 'w':
+			no_withdraw = 1;
+			break;
+
+		case 'D':
+			daemon_debug_opt = 1;
+			break;
+
+		case 'P':
+			plock_debug_opt = 1;
+			break;
+
+		case 'l':
+			plock_rate_limit = atoi(optarg);
+			break;
+
+		case 'p':
+			no_plock = 1;
+			break;
+
+		case 'h':
+			print_usage();
+			exit(EXIT_SUCCESS);
+			break;
+
+		case 'V':
+			printf("gfs_controld (built %s %s)\n", __DATE__, __TIME__);
+			/* printf("%s\n", REDHAT_COPYRIGHT); */
+			exit(EXIT_SUCCESS);
+			break;
+
+		case ':':
+		case '?':
+			fprintf(stderr, "Please use '-h' for usage.\n");
+			exit(EXIT_FAILURE);
+			break;
+
+		case EOF:
+			cont = 0;
+			break;
+
+		default:
+			fprintf(stderr, "unknown option: %c\n", optchar);
+			exit(EXIT_FAILURE);
+			break;
+		};
+	}
+}
+
+void set_oom_adj(int val)
+{
+	FILE *fp;
+
+	fp = fopen("/proc/self/oom_adj", "w");
+	if (!fp)
+		return;
+
+	fprintf(fp, "%i", val);
+	fclose(fp);
+}
+
+void set_scheduler(void)
+{
+	struct sched_param sched_param;
+	int rv;
+
+	rv = sched_get_priority_max(SCHED_RR);
+	if (rv != -1) {
+		sched_param.sched_priority = rv;
+		rv = sched_setscheduler(0, SCHED_RR, &sched_param);
+		if (rv == -1)
+			log_error("could not set SCHED_RR priority %d err %d",
+				   sched_param.sched_priority, errno);
+	} else {
+		log_error("could not get maximum scheduler priority err %d",
+			  errno);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	prog_name = argv[0];
+	INIT_LIST_HEAD(&mounts);
+	INIT_LIST_HEAD(&withdrawn_mounts);
+
+	decode_arguments(argc, argv);
+
+	if (!daemon_debug_opt)
+		daemonize();
+
+	set_scheduler();
+	set_oom_adj(-16);
+
+	return loop();
+}
+
+void daemon_dump_save(void)
+{
+	int len, i;
+
+	len = strlen(daemon_debug_buf);
+
+	for (i = 0; i < len; i++) {
+		dump_buf[dump_point++] = daemon_debug_buf[i];
+
+		if (dump_point == DUMP_SIZE) {
+			dump_point = 0;
+			dump_wrap = 1;
+		}
+	}
+}
+
+char *prog_name;
+int plock_debug_opt;
+int daemon_debug_opt;
+char daemon_debug_buf[256];
+char dump_buf[DUMP_SIZE];
+int dump_point;
+int dump_wrap;
+

Added: branches/cman-based/ocfs2_controld/member_cman.c
===================================================================
--- branches/cman-based/ocfs2_controld/member_cman.c	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/ocfs2_controld/member_cman.c	2007-07-18 00:21:27 UTC (rev 1368)
@@ -0,0 +1,118 @@
+/* -*- 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.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <libcman.h>
+
+#include "ocfs2_controld.h"
+
+int			our_nodeid;
+char *			clustername;
+cman_cluster_t		cluster;
+static cman_handle_t	ch;
+extern struct list_head mounts;
+
+
+static void cman_callback(cman_handle_t h, void *private, int reason, int arg)
+{
+	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);
+		}
+	}
+}
+
+void exit_cman(void)
+{
+	log_error("cluster is down, exiting");
+	exit(1);
+}
+
+int process_cman(void)
+{
+	int rv;
+
+	rv = cman_dispatch(ch, CMAN_DISPATCH_ALL);
+
+	if (rv == -1 && errno == EHOSTDOWN)
+		exit_cman();
+
+	return 0;
+}
+
+int setup_cman(void)
+{
+	cman_node_t node;
+	int rv, fd;
+
+	ch = cman_init(NULL);
+	if (!ch) {
+		log_error("cman_init error %d", errno);
+		return -ENOTCONN;
+	}
+
+	rv = cman_start_notification(ch, cman_callback);
+	if (rv < 0) {
+		log_error("cman_start_notification error %d %d", rv, errno);
+		goto fail_finish;
+	}
+
+	/* FIXME: wait here for us to be a member of the cluster */
+
+	memset(&cluster, 0, sizeof(cluster));
+	rv = cman_get_cluster(ch, &cluster);
+	if (rv < 0) {
+		log_error("cman_get_cluster error %d %d", rv, errno);
+		goto fail_stop;
+	}
+	clustername = cluster.ci_name;
+
+	memset(&node, 0, sizeof(node));
+	rv = cman_get_node(ch, CMAN_NODEID_US, &node);
+	if (rv < 0) {
+		log_error("cman_get_node error %d %d", rv, errno);
+		goto fail_stop;
+	}
+	our_nodeid = node.cn_nodeid;
+
+	fd = cman_get_fd(ch);
+	return fd;
+
+ fail_stop:
+	cman_stop_notification(ch);
+ fail_finish:
+	cman_finish(ch);
+	return rv;
+}
+

Added: branches/cman-based/ocfs2_controld/ocfs2_controld.h
===================================================================
--- branches/cman-based/ocfs2_controld/ocfs2_controld.h	2007-07-16 23:28:31 UTC (rev 1367)
+++ branches/cman-based/ocfs2_controld/ocfs2_controld.h	2007-07-18 00:21:27 UTC (rev 1368)
@@ -0,0 +1,313 @@
+/* -*- 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
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <syslog.h>
+#include <sched.h>
+#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 "list.h"
+#include "linux_endian.h"
+#include "libgroup.h"
+
+#define MAXARGS			16
+#define MAXLINE			256
+#define MAXNAME			255
+#define MAX_CLIENTS		8
+#define MAX_MSGLEN		2048
+#define MAX_OPTIONS_LEN		1024
+#define DUMP_SIZE		(1024 * 1024)
+
+#define OCFS2_CONTROLD_SOCK_PATH	"ocfs2_controld_sock"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+enum {
+	DO_STOP = 1,
+	DO_START,
+	DO_FINISH,
+	DO_TERMINATE,
+	DO_SETID,
+	DO_DELIVER,
+};
+
+extern char *prog_name;
+extern int daemon_debug_opt;
+extern char daemon_debug_buf[256];
+extern char dump_buf[DUMP_SIZE];
+extern int dump_point;
+extern int dump_wrap;
+
+extern void daemon_dump_save(void);
+
+#define log_debug(fmt, args...) \
+do { \
+	snprintf(daemon_debug_buf, 255, "%ld " fmt "\n", time(NULL), ##args); \
+	if (daemon_debug_opt) fprintf(stderr, "%s", daemon_debug_buf); \
+	daemon_dump_save(); \
+} while (0)
+
+#define log_group(g, fmt, args...) \
+do { \
+	snprintf(daemon_debug_buf, 255, "%ld %s " fmt "\n", time(NULL), \
+		 (g)->name, ##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); \
+	syslog(LOG_ERR, fmt, ##args); \
+} while (0)
+
+#define ASSERT(x) \
+{ \
+	if (!(x)) { \
+		fprintf(stderr, "\nAssertion failed on line %d of file %s\n\n" \
+			"Assertion:  \"%s\"\n", \
+			__LINE__, __FILE__, #x); \
+        } \
+}
+
+struct mountpoint {
+	struct list_head	list;
+	char			dir[PATH_MAX+1];
+	int			client;
+};
+
+struct mountgroup {
+	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			type[5];
+	char			options[MAX_OPTIONS_LEN+1];
+	char			dev[PATH_MAX+1];
+
+	int			last_stop;
+	int			last_start;
+	int			last_finish;
+	int			last_callback;
+	int			start_event_nr;
+	int			start_type;
+
+	char			error_msg[128];
+	int			mount_client;
+	int			mount_client_fd;
+	int			mount_client_notified;
+	int			mount_client_delay;
+	int                     group_leave_on_finish;
+	int			remount_client;
+	int			init;
+	int			got_our_options;
+	int			got_our_journals;
+	int			delay_send_journals;
+	int			kernel_mount_error;
+	int			kernel_mount_done;
+	int			got_kernel_mount;
+	int			first_mount_pending_stop;
+	int			first_mounter;
+	int			first_mounter_done;
+	int			global_first_recover_done;
+	int			emulate_first_mounter;
+	int			wait_first_done;
+	int			low_nodeid;
+	int			master_nodeid;
+	int			save_plocks;
+
+	uint64_t		cp_handle;
+	time_t			last_checkpoint_time;
+	time_t			last_plock_time;
+
+	int			needs_recovery;
+	int			our_jid;
+	int			spectator;
+	int			readonly;
+	int			rw;
+	int			withdraw;
+	int			dmsetup_wait;
+	pid_t			dmsetup_pid;
+
+	struct list_head	saved_messages;
+	void			*start2_fn;
+};
+
+/* mg_member opts bit field */
+
+enum {
+	MEMB_OPT_RW		= 1,
+	MEMB_OPT_RO		= 2,
+	MEMB_OPT_SPECT		= 4,
+	MEMB_OPT_RECOVER	= 8,
+};
+
+/* these need to match the kernel defines of the same name in
+   linux/fs/gfs2/lm_interface.h */
+
+#define LM_RD_GAVEUP 308
+#define LM_RD_SUCCESS 309
+
+/* mg_member state: local_recovery_status, recovery_status */
+
+enum {
+	RS_NEED_RECOVERY = 1,
+	RS_SUCCESS,
+	RS_GAVEUP,
+	RS_NOFS,
+	RS_READONLY,
+};
+
+struct mg_member {
+	struct list_head	list;
+	int			nodeid;
+	int			jid;
+
+	int			spectator;
+	int			readonly;
+	int			rw;
+	uint32_t		opts;
+
+	int			tell_gfs_to_recover;
+	int			wait_gfs_recover_done;
+	int			gone_event;
+	int			gone_type;
+	int			finished;
+	int			local_recovery_status;
+	int			recovery_status;
+	int			withdrawing;
+	int			needs_journals;
+
+	int			ms_kernel_mount_done;
+	int			ms_first_mounter;
+	int			ms_kernel_mount_error;
+};
+
+enum {
+	MSG_JOURNAL = 1,
+	MSG_OPTIONS,
+	MSG_REMOUNT,
+	MSG_PLOCK,
+	MSG_WITHDRAW,
+	MSG_MOUNT_STATUS,
+	MSG_RECOVERY_STATUS,
+	MSG_RECOVERY_DONE,
+};
+
+#define GDLM_VER_MAJOR 1
+#define GDLM_VER_MINOR 0
+#define GDLM_VER_PATCH 0
+
+struct gdlm_header {
+	uint16_t		version[3];
+	uint16_t		type;			/* MSG_ */
+	uint32_t		nodeid;			/* sender */
+	uint32_t		to_nodeid;		/* 0 if to all */
+	char			name[MAXNAME];
+};
+
+struct save_msg {
+	struct list_head list;
+	int nodeid;
+	int len;
+	int type;
+	char buf[0];
+};
+
+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_id(uint32_t id);
+
+int setup_cman(void);
+int process_cman(void);
+int setup_cpg(void);
+int process_cpg(void);
+int setup_groupd(void);
+int process_groupd(void);
+int setup_plocks(void);
+int process_plocks(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_remount(int ci, char *dir, char *mode);
+int do_withdraw(char *name);
+int kernel_recovery_done(char *name);
+void ping_kernel_mount(char *table);
+void save_message(struct mountgroup *mg, char *buf, int len, int from, int type);
+void got_mount_result(struct mountgroup *mg, int result, int ci, int another);
+
+int client_send(int ci, char *buf, int len);
+
+int send_group_message(struct mountgroup *mg, int len, char *buf);
+void update_flow_control_status(void);
+
+void store_plocks(struct mountgroup *mg, int nodeid);
+void retrieve_plocks(struct mountgroup *mg);
+int dump_plocks(char *name, int fd);
+void process_saved_plocks(struct mountgroup *mg);
+void purge_plocks(struct mountgroup *mg, int nodeid, int unmount);
+int unlink_checkpoint(struct mountgroup *mg);
+void update_dmsetup_wait(void);
+
+#endif




More information about the Ocfs2-tools-commits mailing list