[Ocfs2-tools-devel] [PATCH 25/32] mkfs.ocfs2: Add --global-heartbeat option
Sunil Mushran
sunil.mushran at oracle.com
Tue Sep 14 15:54:55 PDT 2010
In normal course, we expect users to use tunefs.ocfs2 --update-cluster-stack
to update the disk with the running cluster information. But starting an
o2cb cluster stack with global heartbeat requires a ocfs2 volume with global
heartbeat enabled. The mkfs option has been provided for this reason.
Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
---
mkfs.ocfs2/check.c | 258 ++++++++++++++++++++++++++------------------
mkfs.ocfs2/mkfs.c | 52 +++++++--
mkfs.ocfs2/mkfs.h | 4 +
mkfs.ocfs2/mkfs.ocfs2.8.in | 24 ++++-
4 files changed, 219 insertions(+), 119 deletions(-)
diff --git a/mkfs.ocfs2/check.c b/mkfs.ocfs2/check.c
index 597b87b..f05dc72 100644
--- a/mkfs.ocfs2/check.c
+++ b/mkfs.ocfs2/check.c
@@ -27,12 +27,21 @@
#define WHOAMI "mkfs.ocfs2"
+int is_classic_stack(char *stack_name)
+{
+ return !strcmp(stack_name, OCFS2_CLASSIC_CLUSTER_STACK);
+}
+
/* For ocfs2_fill_cluster_information(). Errors are to be ignored */
-static void cluster_fill(char **stack_name, char **cluster_name)
+void cluster_fill(char **stack_name, char **cluster_name, uint8_t *stack_flags)
{
errcode_t err;
struct o2cb_cluster_desc cluster;
+ *stack_name = NULL;
+ *cluster_name = NULL;
+ *stack_flags = 0;
+
err = o2cb_init();
if (err)
return;
@@ -48,26 +57,28 @@ static void cluster_fill(char **stack_name, char **cluster_name)
*/
*stack_name = cluster.c_stack;
*cluster_name = cluster.c_cluster;
- } else
- *stack_name = strdup("o2cb");
+ *stack_flags = cluster.c_flags;
+ }
}
/* For ocfs2_fill_cluster_information(). Errors are to be ignored */
static void disk_fill(const char *device, char **stack_name,
- char **cluster_name)
+ char **cluster_name, uint8_t *stack_flags)
{
errcode_t err;
ocfs2_filesys *fs = NULL;
struct o2cb_cluster_desc desc;
+ *stack_name = NULL;
+ *cluster_name = NULL;
+ *stack_flags = 0;
+
err = ocfs2_open(device, OCFS2_FLAG_RO, 0, 0, &fs);
if (err)
return;
- if (!ocfs2_clusterinfo_valid(OCFS2_RAW_SB(fs->fs_super))) {
- *stack_name = strdup("o2cb");
+ if (!ocfs2_clusterinfo_valid(OCFS2_RAW_SB(fs->fs_super)))
goto close;
- }
err = ocfs2_fill_cluster_desc(fs, &desc);
if (err)
@@ -75,152 +86,185 @@ static void disk_fill(const char *device, char **stack_name,
*stack_name = strdup(desc.c_stack);
*cluster_name = strdup(desc.c_cluster);
+ *stack_flags = desc.c_flags;
close:
ocfs2_close(fs);
}
-static int pick_one(State *s, const char *what_is_it,
- const char *user_value, const char *o2cb_value,
- const char *disk_value, char **ret_value)
+static int check_cluster_compatibility(State *s, char *active, char *other,
+ const char *other_desc)
{
- int rc = -1;
+ int ret = -1;
- /*
- * First, compare o2cb and disk values. If we get past this
- * block (via match or override), the o2cb value takes precedence.
- */
- if (disk_value && o2cb_value && strcmp(o2cb_value, disk_value)) {
+ if (strlen(other) && strlen(active) && strcmp(active, other)) {
fprintf(stderr,
- "%s is configured to use %s \"%s\", but \"%s\" is currently running.\n"
- "%s will not be able to determine if the filesystem is in use.\n",
- s->device_name, what_is_it,
- disk_value, o2cb_value,
- s->progname);
+ "%s cluster (%s) does not match the active cluster "
+ "(%s).\n%s will not be able to determine if this "
+ "operation can be done safely.\n",
+ other_desc, other, active, s->progname);
if (!s->force) {
fprintf(stderr, "To skip this check, use --force or -F\n");
goto out;
}
- fprintf(stdout, "Overwrite of disk information forced\n");
+ fprintf(stdout, "Format is forced.\n");
}
- if (user_value) {
- if (o2cb_value) {
- if (strcmp(o2cb_value, user_value)) {
- fprintf(stderr, "%s \"%s\" was requested, but \"%s\" is running.\n",
- what_is_it, user_value, o2cb_value);
- if (!s->force) {
- fprintf(stderr,
- "To skip this check, use --force or -F\n");
- goto out;
- }
- fprintf(stdout, "%s forced\n", what_is_it);
- }
- } else if (disk_value) {
- if (strcmp(disk_value, user_value)) {
- fprintf(stderr, "%s \"%s\" was requested, but %s is configured for \"%s\".\n",
- what_is_it, user_value,
- s->device_name, disk_value);
- if (!s->force) {
- fprintf(stderr,
- "To skip this check, use --force or -F\n");
- goto out;
- }
- fprintf(stderr, "%s forced\n", what_is_it);
- }
- }
- *ret_value = strdup(user_value);
- } else if (o2cb_value)
- *ret_value = strdup(o2cb_value);
- else if (disk_value)
- *ret_value = strdup(disk_value);
-
- rc = 0;
-
+ ret = 0;
out:
- return rc;;
+ return ret;
}
/*
* Try to connect to the cluster and look at the disk to fill in default
* cluster values. If we can't connect, that's OK for now. The only errors
* are when values are missing or conflict with option arguments.
+ *
+ * This function assumes that each set of cluster stack values (stack and
+ * cluster name) are either both set or both unset. As in, if the user
+ * specifies a cluster stack, he must specify the cluster name too.
*/
int ocfs2_fill_cluster_information(State *s)
{
- int rc = -1;
- char *user_cluster_name = NULL;
- char *user_stack_name = NULL;
- char *o2cb_cluster_name = NULL;
- char *o2cb_stack_name = NULL;
- char *disk_cluster_name = NULL;
- char *disk_stack_name = NULL;
+ char *user_cluster_name, *user_stack_name, user_value[100];
+ char *o2cb_cluster_name, *o2cb_stack_name, o2cb_value[100];
+ char *disk_cluster_name, *disk_stack_name, disk_value[100];
+ uint8_t user_stack_flags, o2cb_stack_flags, disk_stack_flags;
+ int clusterinfo = 0, userspace = 0;
+ int ret = -1;
if (s->mount == MOUNT_LOCAL)
return 0;
- cluster_fill(&o2cb_stack_name, &o2cb_cluster_name);
- disk_fill(s->device_name, &disk_stack_name, &disk_cluster_name);
+ *user_value = *o2cb_value = *disk_value = '\0';
+
+ /* get currently active cluster stack */
+ cluster_fill(&o2cb_stack_name, &o2cb_cluster_name, &o2cb_stack_flags);
+
+ /* get cluster stack configured on disk */
+ disk_fill(s->device_name, &disk_stack_name, &disk_cluster_name,
+ &disk_stack_flags);
+
+ /* cluster stack as provided by the user */
user_stack_name = s->cluster_stack;
user_cluster_name = s->cluster_name;
+ user_stack_flags = s->stack_flags;
- if (pick_one(s, "cluster stack", user_stack_name, o2cb_stack_name,
- disk_stack_name, &s->cluster_stack))
- return -1;
+ s->cluster_stack = s->cluster_name = NULL;
+ s->stack_flags = 0;
- if (pick_one(s, "cluster name", user_cluster_name,
- o2cb_cluster_name, disk_cluster_name,
- &s->cluster_name))
- return -1;
+ /*
+ * If the user specifies global heartbeat, while we can assume o2cb
+ * stack, we still need to find the cluster name.
+ */
+ if (s->global_heartbeat && !user_stack_name) {
+ if (!o2cb_stack_name) {
+ com_err(s->progname, 0, "Global heartbeat cannot be "
+ "enabled without either starting the o2cb "
+ "cluster stack or providing the cluster stack "
+ "info.");
+ goto out;
+ }
+ if (strcmp(o2cb_stack_name, OCFS2_CLASSIC_CLUSTER_STACK)) {
+ com_err(s->progname, 0, "Global heartbeat is "
+ "incompatible with the active cluster stack "
+ "\"%s\".\n", o2cb_stack_name);
+ goto out;
+ }
- if (s->cluster_stack) {
- if (!strcmp(s->cluster_stack, "o2cb")) {
- /*
- * We've already checked for conflicts above. Now
- * clear out the stack so that fill_super knows
- * it's a classic filesystem.
- */
- free(s->cluster_stack);
- s->cluster_stack = NULL;
- } else if (!s->cluster_name) {
- fprintf(stderr,
- "Cluster name required for stack \"%s\".\n",
- s->cluster_stack);
+ user_stack_name = strdup(o2cb_stack_name);
+ user_cluster_name = strdup(o2cb_cluster_name);
+ user_stack_flags |= OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT;
+ }
+
+ /* User specifically asked for clusterinfo */
+ if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
+ clusterinfo++;
+
+ /* User specifically asked for usersapce stack */
+ if (s->feature_flags.opt_incompat &
+ OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
+ userspace++;
+
+ /* merge - easier to compare */
+ if (user_stack_name && user_cluster_name) {
+ snprintf(user_value, sizeof(user_value), "%s,%s,%d",
+ user_stack_name, user_cluster_name, user_stack_flags);
+ }
+ if (o2cb_stack_name && o2cb_cluster_name) {
+ snprintf(o2cb_value, sizeof(o2cb_value), "%s,%s,%d",
+ o2cb_stack_name, o2cb_cluster_name, o2cb_stack_flags);
+ }
+ if (disk_stack_name && disk_cluster_name) {
+ snprintf(disk_value, sizeof(disk_value), "%s,%s,%d",
+ disk_stack_name, disk_cluster_name, disk_stack_flags);
+ }
+
+ /* if disk and o2cb are not the same, continue only if force set */
+ if (check_cluster_compatibility(s, o2cb_value, disk_value, "On disk"))
+ goto out;
+
+ /* if user and o2cb are not the same, continue only if force set */
+ if (check_cluster_compatibility(s, o2cb_value, user_value,
+ "User requested"))
+ goto out;
+
+ if (strlen(user_value)) {
+ s->cluster_stack = strdup(user_stack_name);
+ s->cluster_name = strdup(user_cluster_name);
+ s->stack_flags = user_stack_flags;
+ } else if (strlen(o2cb_value)) {
+ s->cluster_stack = strdup(o2cb_stack_name);
+ s->cluster_name = strdup(o2cb_cluster_name);
+ s->stack_flags = o2cb_stack_flags;
+ } else if (strlen(disk_value)) {
+ s->cluster_stack = strdup(disk_stack_name);
+ s->cluster_name = strdup(disk_cluster_name);
+ s->stack_flags = disk_stack_flags;
+ } else { /* default */
+ if (clusterinfo || userspace) {
+ fprintf(stderr, "The clusterinfo or userspace stack "
+ "features cannot be enabled. Please rerun with "
+ "the cluster stack details or after starting "
+ "the cluster stack.\n");
goto out;
}
}
- if (!s->cluster_stack && s->cluster_name) {
- /* The classic stack doesn't write a name */
- free(s->cluster_name);
- s->cluster_name = NULL;
+
+ /*
+ * If it is the o2cb stack and the user has not specifically asked
+ * for the clusterinfo feature, then go default.
+ */
+ if (!strlen(user_value) && s->cluster_stack) {
+ if (is_classic_stack(s->cluster_stack) && !clusterinfo &&
+ !s->stack_flags) {
+ free(s->cluster_stack);
+ free(s->cluster_name);
+ s->cluster_stack = s->cluster_name = NULL;
+ s->stack_flags = 0;
+ }
}
+
if (s->cluster_stack) {
fprintf(stdout,
"Cluster stack: %s\n"
"Cluster name: %s\n"
- "NOTE: Selecting extended slot map for userspace "
- "cluster stack\n",
- s->cluster_stack, s->cluster_name);
+ "Stack Flags: 0x%x\n"
+ "NOTE: Feature extended slot map may be enabled\n",
+ s->cluster_stack, s->cluster_name, s->stack_flags);
} else
fprintf(stdout, "Cluster stack: classic o2cb\n");
- rc = 0;
+ ret = 0;
out:
- if (user_stack_name)
- free(user_stack_name);
- if (user_cluster_name)
- free(user_cluster_name);
- if (o2cb_stack_name)
- free(o2cb_stack_name);
- if (o2cb_cluster_name)
- free(o2cb_cluster_name);
- if (disk_stack_name)
- free(disk_stack_name);
- if (disk_cluster_name)
- free(disk_cluster_name);
-
- return rc;
+ free(user_cluster_name);
+ free(user_stack_name);
+ free(o2cb_cluster_name);
+ free(o2cb_stack_name);
+ free(disk_cluster_name);
+ free(disk_stack_name);
+ return ret;
}
int ocfs2_check_volume(State *s)
diff --git a/mkfs.ocfs2/mkfs.c b/mkfs.ocfs2/mkfs.c
index 012fbe6..5cc2bdf 100644
--- a/mkfs.ocfs2/mkfs.c
+++ b/mkfs.ocfs2/mkfs.c
@@ -129,6 +129,7 @@ enum {
FEATURES_OPTION,
CLUSTER_STACK_OPTION,
CLUSTER_NAME_OPTION,
+ GLOBAL_HEARTBEAT_OPTION,
};
static uint64_t align_bytes_to_clusters_ceil(State *s,
@@ -782,6 +783,7 @@ get_state(int argc, char **argv)
char *vol_label = NULL;
char *stack_name = NULL;
char *cluster_name = NULL;
+ int globalhb = 0;
unsigned int initial_slots = 0;
char *dummy;
State *s;
@@ -817,6 +819,7 @@ get_state(int argc, char **argv)
{ "fs-features=", 1, 0, FEATURES_OPTION },
{ "cluster-stack=", 1, 0, CLUSTER_STACK_OPTION },
{ "cluster-name=", 1, 0, CLUSTER_NAME_OPTION },
+ { "global-heartbeat", 0, 0, GLOBAL_HEARTBEAT_OPTION },
{ 0, 0, 0, 0}
};
@@ -1008,6 +1011,10 @@ get_state(int argc, char **argv)
cluster_name = strdup(optarg);
break;
+ case GLOBAL_HEARTBEAT_OPTION:
+ globalhb = 1;
+ break;
+
default:
usage(progname);
break;
@@ -1110,15 +1117,31 @@ get_state(int argc, char **argv)
if (mount != -1)
s->mount = mount;
- if ((stack_name || cluster_name) && (s->mount == MOUNT_LOCAL)) {
+ if ((stack_name || cluster_name || globalhb) &&
+ (s->mount == MOUNT_LOCAL)) {
com_err(progname, 0,
"Local mount is incompatible with specifying a cluster stack");
exit(1);
}
- if (stack_name)
- s->cluster_stack = stack_name;
- if (cluster_name)
- s->cluster_name = cluster_name;
+
+ if (globalhb && stack_name &&
+ strcmp(stack_name, OCFS2_CLASSIC_CLUSTER_STACK)) {
+ com_err(progname, 0, "Global heartbeat is incompatible "
+ "with the cluster stack, %s", stack_name);
+ exit(1);
+ }
+
+ if ((stack_name && !cluster_name) || (!stack_name && cluster_name)) {
+ com_err(progname, 0, "Both cluster stack and the cluster name "
+ "need to be specified");
+ exit(1);
+ }
+
+ s->cluster_stack = stack_name;
+ s->cluster_name = cluster_name;
+ if (globalhb)
+ s->stack_flags |= OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT;
+ s->global_heartbeat = globalhb;
if (no_backup_super != -1)
s->no_backup_super = no_backup_super;
@@ -1258,8 +1281,9 @@ usage(const char *progname)
"[-J journal-options]\n\t\t[-L volume-label] [-M mount-type] "
"[-N number-of-node-slots]\n\t\t[-T filesystem-type] [-HFqvV] "
"\n\t\t[--fs-feature-level=[default|max-compat|max-features]] "
- "\n\t\t[--fs-features=[[no]sparse,...]]"
- "[--no-backup-super] device [blocks-count]\n", progname);
+ "\n\t\t[--fs-features=[[no]sparse,...]] [--global-heartbeat]"
+ "\n\t\t[--cluster-stack=stackname] [--cluster-name=clustername]"
+ "\n\t\t[--no-backup-super] device [blocks-count]\n", progname);
exit(0);
}
@@ -2264,16 +2288,22 @@ format_superblock(State *s, SystemFileDiskRecord *rec,
s->feature_flags.opt_incompat |=
OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP;
+ /* Selectively enable clusterinfo or userspace stack */
if (!(s->feature_flags.opt_incompat &
- OCFS2_FEATURE_INCOMPAT_CLUSTERINFO) &&
- (strcmp(s->cluster_stack, OCFS2_CLASSIC_CLUSTER_STACK))) {
- s->feature_flags.opt_incompat |=
- OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK;
+ OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)) {
+ if (!is_classic_stack(s->cluster_stack))
+ s->feature_flags.opt_incompat |=
+ OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK;
+ else
+ s->feature_flags.opt_incompat |=
+ OCFS2_FEATURE_INCOMPAT_CLUSTERINFO;
}
+
memcpy(di->id2.i_super.s_cluster_info.ci_stack,
s->cluster_stack, OCFS2_STACK_LABEL_LEN);
memcpy(di->id2.i_super.s_cluster_info.ci_cluster,
s->cluster_name, OCFS2_CLUSTER_NAME_LEN);
+ di->id2.i_super.s_cluster_info.ci_stackflags = s->stack_flags;
}
/*
diff --git a/mkfs.ocfs2/mkfs.h b/mkfs.ocfs2/mkfs.h
index c3aecd6..eeb5bcc 100644
--- a/mkfs.ocfs2/mkfs.h
+++ b/mkfs.ocfs2/mkfs.h
@@ -218,6 +218,8 @@ struct _State {
unsigned char *uuid;
char *cluster_stack;
char *cluster_name;
+ uint8_t stack_flags;
+ int global_heartbeat;
uint32_t vol_generation;
int fd;
@@ -237,5 +239,7 @@ struct _State {
enum ocfs2_mkfs_types fs_type;
};
+int is_classic_stack(char *stack_name);
+void cluster_fill(char **stack_name, char **cluster_name, uint8_t *stack_flags);
int ocfs2_fill_cluster_information(State *s);
int ocfs2_check_volume(State *s);
diff --git a/mkfs.ocfs2/mkfs.ocfs2.8.in b/mkfs.ocfs2/mkfs.ocfs2.8.in
index a148133..df4e6e5 100644
--- a/mkfs.ocfs2/mkfs.ocfs2.8.in
+++ b/mkfs.ocfs2/mkfs.ocfs2.8.in
@@ -2,7 +2,7 @@
.SH "NAME"
mkfs.ocfs2 \- Creates an \fIOCFS2\fR file system.
.SH "SYNOPSIS"
-\fBmkfs.ocfs2\fR [\fB\-b\fR \fIblock\-size\fR] [\fB\-C\fR \fIcluster\-size\fR] [\fB\-L\fR \fIvolume\-label\fR] [\fB\-M\fR \fImount-type\fR] [\fB\-N\fR \fInumber\-of\-nodes\fR] [\fB\-J\fR \fIjournal\-options\fR] [\fB\-\-fs\-features=\fR\fI[no]sparse...\fR] [\fB\-\-fs\-feature\-level=\fR\fIfeature\-level\fR] [\fB\-T\fR \fIfilesystem\-type\fR] [\fB\-FqvV\fR] \fIdevice\fR [\fIblocks-count\fI]
+\fBmkfs.ocfs2\fR [\fB\-b\fR \fIblock\-size\fR] [\fB\-C\fR \fIcluster\-size\fR] [\fB\-L\fR \fIvolume\-label\fR] [\fB\-M\fR \fImount-type\fR] [\fB\-N\fR \fInumber\-of\-nodes\fR] [\fB\-J\fR \fIjournal\-options\fR] [\fB\-\-fs\-features=\fR\fI[no]sparse...\fR] [\fB\-\-fs\-feature\-level=\fR\fIfeature\-level\fR] [\fB\-T\fR \fIfilesystem\-type\fR] [\fB\-\-cluster\-stack=\fR\fIstackname\fR] [\fB\-\-cluster\-name=\fR\fIclustername\fR] [\fB\-\-global\-heartbeat\fR] [\fB\-FqvV\fR] \fIdevice\fR [\fIblocks-count\fI]
.SH "DESCRIPTION"
.PP
\fBmkfs.ocfs2\fR is used to create an \fIOCFS2\fR file system on a \fIdevice\fR,
@@ -175,6 +175,7 @@ and number of inodes (files, directories, symbolic links) each group owns. It is
to limit the maximum amount of space or inodes user can have. See a documentation of
quota-tools package for more details.
.RE
+.RS 1.2i
.TP
\fBindexed-dirs\fR
Enable directory indexing support. With this feature enabled, the file system creates indexed tree for non-inline directory entries. For large scale directories, directory entry lookup perfromance from the indexed tree is faster then from the legacy directory blocks.
@@ -200,6 +201,27 @@ Choose the maximum amount of features available. This will typically provide the
.RE
.TP
+\fB\-\-cluster\-stack\fR
+Specify the cluster stack. This option is normally not required as \fBmkfs.ocfs2\fR
+chooses the currently active cluster stack. It is required only if the cluster stack
+is not online and the user wishes to use a stack other than the default,
+\fBO2CB\fR. Other cluster stacks known to work with \fIOCFS2\fR are \fBPCMK\fR
+\fI(Pacemaker)\fR and \fBCMAN\fR. Once set, \fIOCFS2\fR will only allow mounting
+the volume if the active cluster stack (and name) matches the one specified on-disk.
+
+.TP
+\fB\-\-cluster\-name\fR
+Specify the name of the cluster. This option is mandatory if the user has specified
+a \fIcluster\-stack\fR.
+
+.TP
+\fB\-\-global\-heartbeat\fR
+Enable global heartbeat for the \fBO2CB\fR cluster stack. This option is not required
+if the \fBO2CB\fR cluster stack with global heartbeat is online. However, if the
+cluster stack is not up, then this option is required as are \fIcluster\-stack\fR and
+\fIcluster\-name\fR. For more, refer to \fBo2cb(7)\fR.
+
+.TP
\fB\-\-no-backup-super\fR
This option is deprecated, please use \fB--fs-features=nobackup-super\fR instead.
--
1.7.0.4
More information about the Ocfs2-tools-devel
mailing list