fence-agents: master - fence_na: Add support for XML metadata output
by Marek Grác
Gitweb: http://git.fedorahosted.org/git/?p=fence-agents.git;a=commitdiff;h=8bb87b...
Commit: 8bb87b1704ddb923228d3306380250a0908a8877
Parent: dd0e31de6cd4dd6926effaee8824eccc79bbf2a1
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Thu Oct 18 11:35:15 2012 +0200
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Thu Oct 25 10:35:51 2012 +0200
fence_na: Add support for XML metadata output
Adding a skelet for XML metadata output so fence_na can be used with corosync.
Resolves: rhbz#864028
---
fence/agents/node_assassin/fence_na.lib.in | 57 ++++++++++++++++++++++++++++
fence/agents/node_assassin/fence_na.pl | 6 +++
2 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/fence/agents/node_assassin/fence_na.lib.in b/fence/agents/node_assassin/fence_na.lib.in
index 67d5367..dec734a 100644
--- a/fence/agents/node_assassin/fence_na.lib.in
+++ b/fence/agents/node_assassin/fence_na.lib.in
@@ -918,4 +918,61 @@ sub _make_hash_reference
_add_hash_reference($href, $_href);
}
+sub show_metadata
+{
+ print <<METADATA;
+<?xml version="1.0" ?>
+<resource-agent name="fence_na.py" shortdesc="Fence agent for Node Assassin over telnet" >
+<longdesc>fence_na is an I/O Fencing agent which can be used with the Node Assassin network power switch. It logs into device via telnet and reboots a specified outlet. Lengthy telnet/ssh connections should be avoided while a GFS cluster is running because the connection will block any necessary fencing actions.</longdesc>
+<vendor-url>http://www.altavee.ca/w/Node_Assassin_v1.1.4</vendor-url>
+<parameters>
+ <parameter name="action" unique="0" required="1">
+ <getopt mixed="-o <action>" />
+ <content type="string" default="reboot" />
+ <shortdesc lang="en">Fencing Action</shortdesc>
+ </parameter>
+ <parameter name="ipaddr" unique="0" required="1">
+ <getopt mixed="-a <ip>" />
+ <content type="string" />
+ <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ </parameter>
+ <parameter name="login" unique="0" required="1">
+ <getopt mixed="-l <name>" />
+ <content type="string" />
+ <shortdesc lang="en">Login Name</shortdesc>
+ </parameter>
+ <parameter name="passwd" unique="0" required="0">
+ <getopt mixed="-p <password>" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="1">
+ <getopt mixed="-n;" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number</shortdesc>
+ </parameter>
+ <parameter name="version" unique="0" required="0">
+ <getopt mixed="-V" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display version information and exit</shortdesc>
+ </parameter>
+ <parameter name="help" unique="0" required="0">
+ <getopt mixed="-h" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+</parameters>
+<actions>
+ <action name="on" />
+ <action name="off" />
+ <action name="reboot" />
+ <action name="status" />
+ <action name="list" />
+ <action name="monitor" />
+ <action name="metadata" />
+</actions>
+</resource-agent>
+METADATA
+}
+
1;
diff --git a/fence/agents/node_assassin/fence_na.pl b/fence/agents/node_assassin/fence_na.pl
index bc7fb00..bdcaf69 100644
--- a/fence/agents/node_assassin/fence_na.pl
+++ b/fence/agents/node_assassin/fence_na.pl
@@ -106,6 +106,12 @@ foreach my $i (1..$conf->{'system'}{na_num})
}
die "Exiting on errors.\n" if $bad;
+
+if ($conf->{na}{action} eq "metadata") {
+ show_metadata();
+ do_exit($conf, $log, 0);
+}
+
my @ny=("no", "yes");
record($conf, $log, "Node Assassin: . [$conf->{na}{ipaddr}].\n");
record($conf, $log, "TCP Port: ...... [$conf->{na}{tcp_port}].\n");
11 years, 6 months
cluster: RHEL6 - fenced: get the cman fd before each poll
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=1b420aa98fc...
Commit: 1b420aa98fce71f123480dd4eae31e0eb466e864
Parent: 13dcbb8265eafcdf69c033f45f2a37aa44b18908
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Wed Oct 24 14:55:00 2012 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Oct 24 14:55:00 2012 -0500
fenced: get the cman fd before each poll
Prevent rare but possible spinning in poll on the
cman fd.
bz 857952
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
fence/fenced/fd.h | 1 +
fence/fenced/main.c | 5 ++++-
fence/fenced/member_cman.c | 5 +++++
3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/fence/fenced/fd.h b/fence/fenced/fd.h
index 0be3332..205836c 100644
--- a/fence/fenced/fd.h
+++ b/fence/fenced/fd.h
@@ -270,6 +270,7 @@ int name_to_nodeid(char *name);
struct node *get_new_node(struct fd *fd, int nodeid);
void kick_node_from_cluster(int nodeid);
void set_cman_dirty(void);
+int get_cman_fd(void);
/* recover.c */
diff --git a/fence/fenced/main.c b/fence/fenced/main.c
index 827dab6..8e4f10b 100644
--- a/fence/fenced/main.c
+++ b/fence/fenced/main.c
@@ -739,6 +739,7 @@ void cluster_dead(int ci)
static void loop(void)
{
int rv, i;
+ int cman_fd_pos;
void (*workfn) (int ci);
void (*deadfn) (int ci);
@@ -754,7 +755,7 @@ static void loop(void)
rv = setup_cluster();
if (rv < 0)
goto out;
- client_add(rv, process_cluster, cluster_dead);
+ cman_fd_pos = client_add(rv, process_cluster, cluster_dead);
rv = setup_ccs();
if (rv < 0)
@@ -804,6 +805,8 @@ static void loop(void)
}
for (;;) {
+ /* We need to re-get the cman FD each time */
+ pollfd[cman_fd_pos].fd = get_cman_fd();
rv = poll(pollfd, client_maxi + 1, -1);
if (rv == -1 && errno == EINTR) {
if (daemon_quit && list_empty(&domains))
diff --git a/fence/fenced/member_cman.c b/fence/fenced/member_cman.c
index ee879be..a7f4341 100644
--- a/fence/fenced/member_cman.c
+++ b/fence/fenced/member_cman.c
@@ -12,6 +12,11 @@ static int old_node_count;
static cman_node_t cman_nodes[MAX_NODES];
static int cman_node_count;
+int get_cman_fd(void)
+{
+ return cman_get_fd(ch);
+}
+
void set_cman_dirty(void)
{
int rv;
11 years, 6 months
cluster: STABLE32 - fenced: fix potential tight loop reading /dev/zero
by Christine Caulfield
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=4118eaa46e9...
Commit: 4118eaa46e9d2c61c59178dfe17df33d683669f9
Parent: db3b4f9b78de7f90e2e19c590b14e5f3ec57333e
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Tue Oct 23 15:22:31 2012 +0100
Committer: Christine Caulfield <ccaulfie(a)redhat.com>
CommitterDate: Tue Oct 23 15:22:31 2012 +0100
fenced: fix potential tight loop reading /dev/zero
The FD returned from cman is not meant to be stored anywhere - this is documented in the header
file (which is the official source of documentation for the API). Under some circumstances cman
can return the FD for /dev/zero (which is always active) and if the client application stores i
this instead of the one it expects then it will loop forever.
It's probably VERY hard to reproduce this, there would need to be some data coming from cman
quite soon after startup for it to happen, though it has been seen.
See rhbz#856214
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
fence/fenced/fd.h | 1 +
fence/fenced/main.c | 5 ++++-
fence/fenced/member_cman.c | 5 +++++
3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/fence/fenced/fd.h b/fence/fenced/fd.h
index 0be3332..8423d9d 100644
--- a/fence/fenced/fd.h
+++ b/fence/fenced/fd.h
@@ -270,6 +270,7 @@ int name_to_nodeid(char *name);
struct node *get_new_node(struct fd *fd, int nodeid);
void kick_node_from_cluster(int nodeid);
void set_cman_dirty(void);
+int get_member_fd(void);
/* recover.c */
diff --git a/fence/fenced/main.c b/fence/fenced/main.c
index 2339a5d..c7f6269 100644
--- a/fence/fenced/main.c
+++ b/fence/fenced/main.c
@@ -739,6 +739,7 @@ void cluster_dead(int ci)
static void loop(void)
{
int rv, i;
+ int cluster_fd_pos;
void (*workfn) (int ci);
void (*deadfn) (int ci);
@@ -751,7 +752,7 @@ static void loop(void)
goto out;
client_add(rv, process_listener, NULL);
- rv = setup_cluster();
+ rv = cluster_fd_pos = setup_cluster();
if (rv < 0)
goto out;
client_add(rv, process_cluster, cluster_dead);
@@ -804,6 +805,8 @@ static void loop(void)
}
for (;;) {
+ /* We need to re-get the cluster FD each time */
+ pollfd[cluster_fd_pos].fd = get_member_fd();
rv = poll(pollfd, client_maxi + 1, -1);
if (rv == -1 && errno == EINTR) {
if (daemon_quit && list_empty(&domains))
diff --git a/fence/fenced/member_cman.c b/fence/fenced/member_cman.c
index ee879be..061136e 100644
--- a/fence/fenced/member_cman.c
+++ b/fence/fenced/member_cman.c
@@ -375,6 +375,11 @@ void close_cluster(void)
cman_finish(ch_admin);
}
+int get_member_fd()
+{
+ return cman_get_fd(ch);
+}
+
struct node *get_new_node(struct fd *fd, int nodeid)
{
cman_node_t cn;
11 years, 6 months
gfs2-utils: master - libgfs2: Add a gfs2 block query language
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=ad15965a...
Commit: ad15965a9449e68dc83aa21190262c493089f05d
Parent: 24fad71d36ecce70a5d0d4206d0b13e7b77ec94c
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri Oct 12 18:25:41 2012 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Mon Oct 15 15:26:33 2012 +0100
libgfs2: Add a gfs2 block query language
This patch adds a small language which we can use to write libgfs2 and
gfs2-utils tests (among other things). It provides 'get' and 'set'
statements which look up and modify gfs2 blocks. The language API is
defined as:
struct lgfs2_lang_state;
struct lgfs2_lang_result {
uint64_t lr_blocknr;
struct gfs2_buffer_head *lr_bh;
const struct lgfs2_metadata *lr_mtype;
int lr_state; // GFS2_BLKST_*
};
struct lgfs2_lang_state *lgfs2_lang_init(void);
void lgfs2_lang_free(struct lgfs2_lang_state **state);
int lgfs2_lang_parsef(struct lgfs2_lang_state *state, FILE *script);
int lgfs2_lang_parses(struct lgfs2_lang_state *state, const char *script);
struct lgfs2_lang_result *lgfs2_lang_result_next(struct lgfs2_lang_state *state, struct gfs2_sbd *sbd);
int lgfs2_lang_result_print(struct lgfs2_lang_result *result);
void lgfs2_lang_result_free(struct lgfs2_lang_result **result);
The lgfs2_lang_parse{s,f} functions allow you to parse a string or a
file respectively. Using the same state object you can then run the same
script multiple times, without parsing it again. The intended usage of
these functions can be shown with a simple example (error checking
omitted):
struct lgfs2_lang_state *state = lgfs2_lang_init();
lgfs2_lang_parses(state, "get sb; get 1234 state; set '/foo/bar' {di_entries: 3}");
for (result = lgfs2_lang_result_next(state, &sbd);
result != NULL;
result = lgfs2_lang_result_next(state, &sbd)) {
lgfs2_lang_result_print(result);
lgfs2_lang_result_free(&result);
}
lgfs2_lang_free(&state);
The language has a simple syntax:
get <block_lookup> [state]
set <block_lookup> {<field0>:<value0>, <field1>:<value1>, ... }
A block lookup can be a file system block address (1234 or 0x1234), a
resource group subscript (rgrp[0], rgrp[0x5]), a keyword (sb, master,
root, rindex) or an offset from any of the above (1234+5, rgrp[1]+23,
rindex+68, ...).
After the block lookup, the 'get' statement takes an optional keyword
'state' which allows you to query the bitmap state of the block.
Examples of 'get':
get rgrp[1]+23 state
--> result.lr_state == GFS2_BLKST_FREE
get rindex
--> result.lr_bh is a buffer containing the rindex dinode.
--> result.lr_mtype is the block's metatype as defined in meta.c.
The 'set' statement requires a list of field-value pairs which are to be
modified in the block. The field names must match the names shown when
running the 'get' statement with the same block lookup.
Examples of 'set':
set '/foo/bar/baz' { di_entries: 3 }
--> result.lr_bh contains the dinode block at path /foo/bar/baz, with
the di_entries field modified.
--> result.lr_mtype is the block's metatype as defined in meta.c.
set sb { sb_lockproto: 'lock_dlm', sb_bsize: 0x1000 }
--> result.lr_bh contains the superblock with the lockproto changed to
lock_dlm and the block size changed to 4096.
--> result.lr_mtype is the block's metatype as defined in meta.c.
Whitespace is insignificant in the language and semicolons can be used
to separate multiple statements. When writing longer scripts spanning
multiple lines, C-like // syntax can be used to insert comments.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
.gitignore | 7 +
configure.ac | 2 +
gfs2/libgfs2/Makefile.am | 13 +-
gfs2/libgfs2/buf.c | 10 +
gfs2/libgfs2/fs_ops.c | 6 +-
gfs2/libgfs2/lang.c | 603 ++++++++++++++++++++++++++++++++++++++++++++++
gfs2/libgfs2/lang.h | 61 +++++
gfs2/libgfs2/lexer.l | 101 ++++++++
gfs2/libgfs2/libgfs2.h | 24 ++
gfs2/libgfs2/meta.c | 50 ++++
gfs2/libgfs2/misc.c | 2 -
gfs2/libgfs2/parser.y | 186 ++++++++++++++
gfs2/libgfs2/super.c | 2 +-
13 files changed, 1057 insertions(+), 10 deletions(-)
diff --git a/.gitignore b/.gitignore
index e8b7ea1..4e3071a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,9 @@ make/stamp-h1
m4
make/clusterautoconfig.h*
missing
+ylwrap
+cscope.out
+.gdb_history
*.pc
.deps
.libs
@@ -29,6 +32,10 @@ missing
*.lo
gfs2/convert/gfs2_convert
gfs2/edit/gfs2_edit
+gfs2/libgfs2/parser.c
+gfs2/libgfs2/parser.h
+gfs2/libgfs2/lexer.c
+gfs2/libgfs2/lexer.h
gfs2/fsck/fsck.gfs2
gfs2/mkfs/mkfs.gfs2
gfs2/mount/mount.gfs2
diff --git a/configure.ac b/configure.ac
index d56cfac..ef09569 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,8 @@ AM_PROG_CC_C_O
AC_PROG_LN_S
AC_PROG_INSTALL
AC_PROG_MAKE_SET
+AC_PROG_LEX
+AC_PROG_YACC
## local helper functions
diff --git a/gfs2/libgfs2/Makefile.am b/gfs2/libgfs2/Makefile.am
index 4e60b0a..7103e09 100644
--- a/gfs2/libgfs2/Makefile.am
+++ b/gfs2/libgfs2/Makefile.am
@@ -1,15 +1,24 @@
MAINTAINERCLEANFILES = Makefile.in
-noinst_HEADERS = libgfs2.h
+CLEANFILES = parser.h parser.c lexer.c lexer.h
+BUILT_SOURCES = parser.h lexer.h
+AM_LFLAGS = --header-file=lexer.h
+AM_YFLAGS = -d
+
+noinst_HEADERS = libgfs2.h lang.h
noinst_LTLIBRARIES = libgfs2.la
libgfs2_la_SOURCES = block_list.c fs_bits.c gfs1.c misc.c rgrp.c super.c \
buf.c fs_geometry.c gfs2_disk_hash.c ondisk.c \
device_geometry.c fs_ops.c gfs2_log.c recovery.c \
- structures.c meta.c
+ structures.c meta.c lang.c parser.y lexer.l
libgfs2_la_CPPFLAGS = -D_FILE_OFFSET_BITS=64 \
-D_LARGEFILE64_SOURCE \
-D_GNU_SOURCE \
-I$(top_srcdir)/gfs2/include
+
+# Autotools can't handle header files output by flex so we have to generate it manually
+lexer.h: lexer.l
+ $(LEX) -o lexer.c $(AM_LFLAGS) $^
diff --git a/gfs2/libgfs2/buf.c b/gfs2/libgfs2/buf.c
index 956dd8b..5bc1a4e 100644
--- a/gfs2/libgfs2/buf.c
+++ b/gfs2/libgfs2/buf.c
@@ -83,3 +83,13 @@ int brelse(struct gfs2_buffer_head *bh)
free(bh);
return error;
}
+
+uint32_t lgfs2_get_block_type(const struct gfs2_buffer_head *lbh)
+{
+ const struct gfs2_meta_header *mh = lbh->iov.iov_base;
+
+ if (be32_to_cpu(mh->mh_magic) == GFS2_MAGIC)
+ return be32_to_cpu(mh->mh_type);
+
+ return 0;
+}
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index ec150e8..3d027e8 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1759,11 +1759,7 @@ int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
return 0;
}
error = dir_search(dip, filename, len, NULL, &inum);
- if (error) {
- if (error == -ENOENT)
- return 0;
- }
- else
+ if (!error)
*ipp = lgfs2_inode_read(sdp, inum.no_addr);
return error;
diff --git a/gfs2/libgfs2/lang.c b/gfs2/libgfs2/lang.c
new file mode 100644
index 0000000..12ca7bd
--- /dev/null
+++ b/gfs2/libgfs2/lang.c
@@ -0,0 +1,603 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "parser.h"
+#include "lang.h"
+
+const char* ast_type_string[] = {
+ [AST_NONE] = "NONE",
+ // Statements
+ [AST_ST_SET] = "SET",
+ [AST_ST_GET] = "GET",
+
+ // Expressions
+ [AST_EX_ID] = "IDENTIFIER",
+ [AST_EX_NUMBER] = "NUMBER",
+ [AST_EX_STRING] = "STRING",
+ [AST_EX_ADDRESS] = "ADDRESS",
+ [AST_EX_PATH] = "PATH",
+ [AST_EX_SUBSCRIPT] = "SUBSCRIPT",
+ [AST_EX_OFFSET] = "OFFSET",
+ [AST_EX_BLOCKSPEC] = "BLOCKSPEC",
+ [AST_EX_STRUCTSPEC] = "STRUCTSPEC",
+ [AST_EX_FIELDSPEC] = "FIELDSPEC",
+
+ // Keywords
+ [AST_KW_STATE] = "STATE",
+};
+
+/**
+ * Initialize an expression node of the given type from a source string.
+ * Currently just converts numerical values and string values where
+ * appropriate. String values are duplicted into newly allocated buffers as the
+ * text from the parser will go away.
+ * Returns 0 on success or non-zero with errno set on failure
+ */
+static int ast_expr_init(struct ast_node *expr, ast_node_t type, const char *str)
+{
+ int ret = 0;
+ switch (type) {
+ case AST_EX_OFFSET:
+ str++; // Cut off the +
+ case AST_EX_NUMBER:
+ ret = sscanf(str, "%"SCNi64, &expr->ast_num);
+ if (ret != 1) {
+ return 1;
+ }
+ break;
+ case AST_EX_ID:
+ case AST_EX_PATH:
+ case AST_EX_STRING:
+ expr->ast_str = strdup(str);
+ if (expr->ast_str == NULL) {
+ return 1;
+ }
+ break;
+ case AST_EX_ADDRESS:
+ case AST_EX_SUBSCRIPT:
+ case AST_EX_BLOCKSPEC:
+ case AST_EX_STRUCTSPEC:
+ case AST_EX_FIELDSPEC:
+ case AST_KW_STATE:
+ break;
+ default:
+ errno = EINVAL;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Create a new AST node of a given type from a source string.
+ * Returns a pointer to the new node or NULL on failure with errno set.
+ */
+struct ast_node *ast_new(ast_node_t type, const char *text)
+{
+ struct ast_node *node;
+ node = (struct ast_node *)calloc(1, sizeof(struct ast_node));
+ if (node == NULL) {
+ goto return_fail;
+ }
+
+ if (type > _AST_EX_START && ast_expr_init(node, type, text)) {
+ goto return_free;
+ }
+
+ node->ast_text = strdup(text);
+ if (node->ast_text == NULL) {
+ goto return_free;
+ }
+ node->ast_type = type;
+
+ return node;
+
+return_free:
+ if (node->ast_text) {
+ free(node->ast_text);
+ }
+ if (node->ast_str) {
+ free(node->ast_str);
+ }
+ free(node);
+return_fail:
+ fprintf(stderr, "Failed to create new value from %s: %s\n", text, strerror(errno));
+ return NULL;
+}
+
+/**
+ * Free the memory allocated for an AST node and set its pointer to NULL
+ */
+void ast_destroy(struct ast_node **node)
+{
+ if (*node == NULL) {
+ return;
+ }
+ ast_destroy(&(*node)->ast_left);
+ ast_destroy(&(*node)->ast_right);
+ switch((*node)->ast_type) {
+ case AST_EX_ID:
+ case AST_EX_PATH:
+ case AST_EX_STRING:
+ free((*node)->ast_str);
+ break;
+ default:
+ break;
+ }
+ free((*node)->ast_text);
+ free(*node);
+ *node = NULL;
+}
+
+static void ast_string_unescape(char *str)
+{
+ int head, tail;
+ for (head = tail = 0; str[head] != '\0'; head++, tail++) {
+ if (str[head] == '\\' && str[head+1] != '\0')
+ head++;
+ str[tail] = str[head];
+ }
+ str[tail] = '\0';
+}
+
+static uint64_t ast_lookup_path(char *path, struct gfs2_sbd *sbd)
+{
+ int err = 0;
+ char *c;
+ struct gfs2_inode *ip, *iptmp;
+ char *segment;
+ uint64_t bn = 0;
+
+ segment = strtok_r(path, "/", &c);
+ ip = lgfs2_inode_read(sbd, sbd->sd_sb.sb_root_dir.no_addr);
+
+ while (ip != NULL) {
+ if (segment == NULL) { // No more segments
+ bn = ip->i_di.di_num.no_addr;
+ inode_put(&ip);
+ return bn;
+ }
+ ast_string_unescape(segment);
+ err = gfs2_lookupi(ip, segment, strlen(segment), &iptmp);
+ inode_put(&ip);
+ if (err != 0) {
+ errno = -err;
+ break;
+ }
+ ip = iptmp;
+ segment = strtok_r(NULL, "/", &c);
+ }
+
+ perror("Path lookup");
+ return 0;
+}
+
+enum block_id {
+ ID_SB = 0,
+ ID_MASTER,
+ ID_ROOT,
+ ID_RINDEX,
+
+ ID_END
+};
+
+/**
+ * Names of blocks which can be uniquely identified in the fs
+ */
+static const char *block_ids[] = {
+ [ID_SB] = "sb",
+ [ID_MASTER] = "master",
+ [ID_ROOT] = "root",
+ [ID_RINDEX] = "rindex",
+
+ [ID_END] = NULL
+};
+
+static uint64_t ast_lookup_id(const char *id, struct gfs2_sbd *sbd)
+{
+ uint64_t bn = 0;
+ int i;
+ for (i = 0; i < ID_END; i++) {
+ if (!strcmp(id, block_ids[i])) {
+ break;
+ }
+ }
+ switch (i) {
+ case ID_SB:
+ bn = sbd->sb_addr;
+ break;
+ case ID_MASTER:
+ bn = sbd->sd_sb.sb_master_dir.no_addr;
+ break;
+ case ID_ROOT:
+ bn = sbd->sd_sb.sb_root_dir.no_addr;
+ break;
+ case ID_RINDEX:
+ bn = sbd->md.riinode->i_di.di_num.no_addr;
+ break;
+ default:
+ return 0;
+ }
+ return bn;
+}
+
+static uint64_t ast_lookup_rgrp(uint64_t rgnum, struct gfs2_sbd *sbd)
+{
+ uint64_t i = rgnum;
+ struct osi_node *n;
+
+ for (n = osi_first(&sbd->rgtree); n != NULL && i > 0; n = osi_next(n), i--);
+ if (n != NULL && i == 0)
+ return ((struct rgrp_tree *)n)->ri.ri_addr;
+ fprintf(stderr, "Resource group number out of range: %"PRIu64"\n", rgnum);
+ return 0;
+}
+
+static uint64_t ast_lookup_subscript(struct ast_node *id, struct ast_node *index,
+ struct gfs2_sbd *sbd)
+{
+ uint64_t bn = 0;
+ const char *name = id->ast_str;
+ if (!strcmp(name, "rgrp")) {
+ bn = ast_lookup_rgrp(index->ast_num, sbd);
+ } else {
+ fprintf(stderr, "Unrecognized identifier %s\n", name);
+ }
+ return bn;
+}
+
+/**
+ * Look up a block and return its number. The kind of lookup depends on the
+ * type of the ast node.
+ */
+static uint64_t ast_lookup_block_num(struct ast_node *ast, struct gfs2_sbd *sbd)
+{
+ uint64_t bn = 0;
+ switch (ast->ast_type) {
+ case AST_EX_OFFSET:
+ bn = ast_lookup_block_num(ast->ast_left, sbd) + ast->ast_num;
+ break;
+ case AST_EX_ADDRESS:
+ bn = ast->ast_num;
+ break;
+ case AST_EX_PATH:
+ bn = ast_lookup_path(ast->ast_str, sbd);
+ break;
+ case AST_EX_ID:
+ bn = ast_lookup_id(ast->ast_str, sbd);
+ break;
+ case AST_EX_SUBSCRIPT:
+ bn = ast_lookup_subscript(ast->ast_left, ast->ast_left->ast_left, sbd);
+ break;
+ default:
+ break;
+ }
+ return bn;
+}
+
+static struct gfs2_buffer_head *ast_lookup_block(struct ast_node *node, struct gfs2_sbd *sbd)
+{
+ uint64_t bn = ast_lookup_block_num(node, sbd);
+ if (bn == 0) {
+ return NULL;
+ }
+
+ return bread(sbd, bn);
+}
+
+static const char *bitstate_strings[] = {
+ [GFS2_BLKST_FREE] = "Free",
+ [GFS2_BLKST_USED] = "Used",
+ [GFS2_BLKST_UNLINKED] = "Unlinked",
+ [GFS2_BLKST_DINODE] = "Dinode"
+};
+
+/**
+ * Print a representation of an arbitrary GFS2 block to stdout
+ */
+int lgfs2_lang_result_print(struct lgfs2_lang_result *result)
+{
+ int i;
+ if (result->lr_mtype != NULL) {
+ for (i = 0; i < result->lr_mtype->nfields; i++) {
+ lgfs2_field_print(result->lr_bh, result->lr_mtype, &result->lr_mtype->fields[i]);
+ }
+ } else {
+ printf("%"PRIu64": %s\n", result->lr_blocknr, bitstate_strings[result->lr_state]);
+ }
+ return 0;
+}
+
+static int ast_get_bitstate(uint64_t bn, struct gfs2_sbd *sbd)
+{
+ int ret = 0;
+ int state = 0;
+ struct rgrp_tree *rgd = gfs2_blk2rgrpd(sbd, bn);
+ if (rgd == NULL) {
+ fprintf(stderr, "Could not find resource group for block %"PRIu64"\n", bn);
+ return -1;
+ }
+
+ ret = gfs2_rgrp_read(sbd, rgd);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to read resource group for block %"PRIu64": %d\n", bn, ret);
+ return -1;
+ }
+
+ state = gfs2_get_bitmap(sbd, bn, rgd);
+ if (state == -1) {
+ fprintf(stderr, "Failed to acquire bitmap state for block %"PRIu64"\n", bn);
+ return -1;
+ }
+
+ gfs2_rgrp_relse(rgd);
+ return state;
+}
+
+static const struct lgfs2_metadata *ast_lookup_mtype(const struct gfs2_buffer_head *bh)
+{
+ const struct lgfs2_metadata *mtype;
+ const uint32_t mh_type = lgfs2_get_block_type(bh);
+ if (mh_type == 0) {
+ fprintf(stderr, "Could not determine type for block %"PRIu64"\n", bh->b_blocknr);
+ return NULL;
+ }
+
+ mtype = lgfs2_find_mtype(mh_type, bh->sdp->gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2);
+ if (mtype == NULL) {
+ fprintf(stderr, "Could not determine meta type for block %"PRIu64"\n", bh->b_blocknr);
+ return NULL;
+ }
+ return mtype;
+}
+
+/**
+ * Interpret the get statement.
+ */
+static struct lgfs2_lang_result *ast_interp_get(struct lgfs2_lang_state *state,
+ struct ast_node *ast, struct gfs2_sbd *sbd)
+{
+ struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
+ if (result == NULL) {
+ fprintf(stderr, "Failed to allocate memory for result\n");
+ return NULL;
+ }
+
+ if (ast->ast_right->ast_right == NULL) {
+ result->lr_bh = ast_lookup_block(ast->ast_right, sbd);
+ if (result->lr_bh == NULL) {
+ free(result);
+ return NULL;
+ }
+ result->lr_blocknr = result->lr_bh->b_blocknr;
+ result->lr_mtype = ast_lookup_mtype(result->lr_bh);
+
+ } else if (ast->ast_right->ast_right->ast_type == AST_KW_STATE) {
+ result->lr_blocknr = ast_lookup_block_num(ast->ast_right, sbd);
+ if (result->lr_blocknr == 0) {
+ return NULL;
+ }
+ result->lr_state = ast_get_bitstate(result->lr_blocknr, sbd);
+ }
+
+ return result;
+}
+
+/**
+ * Interpret a UUID string by removing hyphens from the string and then
+ * interprets 16 pairs of hex digits as octets.
+ */
+static int ast_str_to_uuid(const char *str, uint8_t *uuid)
+{
+ char s[33];
+ int head, tail, tmp;
+
+ for (head = tail = 0; head < strlen(str) && tail < 33; head++) {
+ if (str[head] == '-')
+ continue;
+ s[tail] = tolower(str[head]);
+ if (!((s[tail] >= 'a' && s[tail] <= 'f') ||
+ (s[tail] >= '0' && s[tail] <= '9')))
+ goto invalid;
+ tail++;
+ }
+ if (tail != 32) {
+ goto invalid;
+ }
+ s[tail] = '\0';
+ for (head = 0; head < 16; head++) {
+ if (sscanf(s+(head*2), "%02x", &tmp) != 1) {
+ goto invalid;
+ }
+ *(uuid + head) = tmp;
+ }
+ return AST_INTERP_SUCCESS;
+invalid:
+ fprintf(stderr, "Invalid UUID\n");
+ return AST_INTERP_INVAL;
+}
+
+/**
+ * Set a field of a gfs2 block of a given type to a given value.
+ * Returns AST_INTERP_* to signal success, an invalid field/value or an error.
+ */
+static int ast_field_set(struct gfs2_buffer_head *bh, const struct lgfs2_metafield *field,
+ struct ast_node *val)
+{
+ char *fieldp = (char *)bh->iov.iov_base + field->offset;
+
+ if (field->flags & LGFS2_MFF_UUID) {
+ uint8_t uuid[16];
+ int ret = ast_str_to_uuid(val->ast_str, uuid);
+
+ if (ret != AST_INTERP_SUCCESS)
+ return ret;
+
+ memcpy(fieldp, uuid, 16);
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ }
+
+ if ((field->flags & LGFS2_MFF_STRING) && strlen(val->ast_str) > field->length) {
+ fprintf(stderr, "String '%s' is too long for field '%s'\n", val->ast_str, field->name);
+ return AST_INTERP_INVAL;
+ }
+
+ if (field->flags & (LGFS2_MFF_STRING|LGFS2_MFF_UUID)) {
+ strncpy(fieldp, val->ast_str, field->length - 1);
+ fieldp[field->length - 1] = '\0';
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ } else {
+ // Numeric fields
+ switch(field->length) {
+ case 1:
+ if (val->ast_num > UINT8_MAX)
+ break;
+ *fieldp = (uint8_t)val->ast_num;
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ case 2:
+ if (val->ast_num > UINT16_MAX)
+ break;
+ *(uint16_t *)fieldp = cpu_to_be16((uint16_t)val->ast_num);
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ case 4:
+ if (val->ast_num > UINT32_MAX)
+ break;
+ *(uint32_t *)fieldp = cpu_to_be32((uint32_t)val->ast_num);
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ case 8:
+ *(uint64_t *)fieldp = cpu_to_be64((uint64_t)val->ast_num);
+ bmodified(bh);
+ return AST_INTERP_SUCCESS;
+ default:
+ // This should never happen
+ return AST_INTERP_ERR;
+ }
+ }
+
+ fprintf(stderr, "Invalid field assignment: %s (size %d) = %s\n",
+ field->name, field->length, val->ast_text);
+ return AST_INTERP_INVAL;
+}
+
+/**
+ * Interpret an assignment (set)
+ */
+static struct lgfs2_lang_result *ast_interp_set(struct lgfs2_lang_state *state,
+ struct ast_node *ast, struct gfs2_sbd *sbd)
+{
+ struct ast_node *lookup = ast->ast_right;
+ struct ast_node *fieldspec;
+ struct ast_node *fieldname;
+ struct ast_node *fieldval;
+ uint32_t mh_type = 0;
+ int i = 0;
+ int ret = 0;
+
+ struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
+ if (result == NULL) {
+ fprintf(stderr, "Failed to allocate memory for result\n");
+ return NULL;
+ }
+
+ result->lr_bh = ast_lookup_block(lookup, sbd);
+ if (result->lr_bh == NULL) {
+ goto out_err;
+ }
+
+ mh_type = lgfs2_get_block_type(result->lr_bh);
+ if (mh_type == 0) {
+ goto out_err;
+ }
+
+ result->lr_mtype = lgfs2_find_mtype(mh_type, sbd->gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2);
+ if (result->lr_mtype == NULL) {
+ goto out_err;
+ }
+
+ for (fieldspec = lookup->ast_right;
+ fieldspec != NULL && fieldspec->ast_type == AST_EX_FIELDSPEC;
+ fieldspec = fieldspec->ast_left) {
+
+ fieldname = fieldspec->ast_right;
+ fieldval = fieldname->ast_right;
+ for (i = 0; i < result->lr_mtype->nfields; i++) {
+ if (!strcmp(result->lr_mtype->fields[i].name, fieldname->ast_str)) {
+ ret = ast_field_set(result->lr_bh, &result->lr_mtype->fields[i], fieldval);
+ if (ret != AST_INTERP_SUCCESS) {
+ goto out_err;
+ }
+ break;
+ }
+ }
+ }
+
+ ret = bwrite(result->lr_bh);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to write modified block %"PRIu64": %s\n",
+ result->lr_bh->b_blocknr, strerror(errno));
+ goto out_err;
+ }
+
+ return result;
+
+out_err:
+ lgfs2_lang_result_free(&result);
+ return NULL;
+}
+
+static struct lgfs2_lang_result *ast_interpret_node(struct lgfs2_lang_state *state,
+ struct ast_node *ast, struct gfs2_sbd *sbd)
+{
+ struct lgfs2_lang_result *result = NULL;
+
+ if (ast->ast_type == AST_ST_SET) {
+ result = ast_interp_set(state, ast, sbd);
+ } else if (ast->ast_type == AST_ST_GET) {
+ result = ast_interp_get(state, ast, sbd);
+ } else {
+ fprintf(stderr, "Invalid AST node type: %d\n", ast->ast_type);
+ }
+ return result;
+}
+
+struct lgfs2_lang_result *lgfs2_lang_result_next(struct lgfs2_lang_state *state,
+ struct gfs2_sbd *sbd)
+{
+ struct lgfs2_lang_result *result;
+ if (state->ls_interp_curr == NULL) {
+ return NULL;
+ }
+ result = ast_interpret_node(state, state->ls_interp_curr, sbd);
+ if (result == NULL) {
+ return NULL;
+ }
+ state->ls_interp_curr = state->ls_interp_curr->ast_left;
+ return result;
+}
+
+void lgfs2_lang_result_free(struct lgfs2_lang_result **result)
+{
+ if (*result == NULL) {
+ fprintf(stderr, "Warning: attempted to free a null result\n");
+ return;
+ }
+
+ if ((*result)->lr_mtype != NULL) {
+ (*result)->lr_bh->b_modified = 0;
+ brelse((*result)->lr_bh);
+ (*result)->lr_bh = NULL;
+ }
+
+ free(*result);
+ *result = NULL;
+}
diff --git a/gfs2/libgfs2/lang.h b/gfs2/libgfs2/lang.h
new file mode 100644
index 0000000..955e52e
--- /dev/null
+++ b/gfs2/libgfs2/lang.h
@@ -0,0 +1,61 @@
+#ifndef LANG_H
+#define LANG_H
+#include <stdint.h>
+#include "libgfs2.h"
+
+struct lgfs2_lang_state {
+ int ls_colnum;
+ int ls_linenum;
+ int ls_errnum;
+ struct ast_node *ls_ast_root;
+ struct ast_node *ls_ast_tail;
+ struct ast_node *ls_interp_curr;
+};
+
+typedef enum {
+ AST_NONE,
+ // Statements
+ AST_ST_SET,
+ AST_ST_GET,
+
+ _AST_EX_START,
+ // Expressions
+ AST_EX_ID,
+ AST_EX_NUMBER,
+ AST_EX_STRING,
+ AST_EX_ADDRESS,
+ AST_EX_PATH,
+ AST_EX_SUBSCRIPT,
+ AST_EX_OFFSET,
+ AST_EX_BLOCKSPEC,
+ AST_EX_STRUCTSPEC,
+ AST_EX_FIELDSPEC,
+
+ // Keywords
+ AST_KW_STATE,
+} ast_node_t;
+
+enum {
+ AST_INTERP_SUCCESS = 0, // Success
+ AST_INTERP_FAIL = 1, // Failure
+ AST_INTERP_INVAL = 2, // Invalid field/type mismatch
+ AST_INTERP_ERR = 3, // Something went wrong, see errno
+};
+
+extern const char* ast_type_string[];
+
+struct ast_node {
+ ast_node_t ast_type;
+ struct ast_node *ast_left;
+ struct ast_node *ast_right;
+ char *ast_text;
+ char *ast_str;
+ uint64_t ast_num;
+};
+
+extern struct ast_node *ast_new(ast_node_t type, const char *text);
+extern void ast_destroy(struct ast_node **val);
+
+#define YYSTYPE struct ast_node *
+
+#endif /* LANG_H */
diff --git a/gfs2/libgfs2/lexer.l b/gfs2/libgfs2/lexer.l
new file mode 100644
index 0000000..36e1c2d
--- /dev/null
+++ b/gfs2/libgfs2/lexer.l
@@ -0,0 +1,101 @@
+%{
+#include "lang.h"
+#include "parser.h"
+
+#define EXTRA ((struct lgfs2_lang_state *)yyextra)
+
+#define P(token, type, text) do {\
+ *(yylval) = ast_new(type, text);\
+ if (*(yylval) == NULL) {\
+ EXTRA->ls_errnum = errno;\
+ return 1;\
+ }\
+ return (TOK_##token);\
+} while(0)
+
+#define COLNUM EXTRA->ls_colnum
+#define YY_USER_ACTION COLNUM += yyleng;
+
+%}
+%option bison-bridge reentrant
+%option warn debug
+%option nounput noinput
+%option noyywrap
+%option extra-type="struct lgfs2_lang_state *"
+
+letter [a-zA-Z_]
+decdigit [0-9]
+decnumber -?{decdigit}+
+hexdigit [0-9a-fA-F]
+hexnumber -?0x{hexdigit}+
+number ({decnumber}|{hexnumber})
+offset \+{number}
+id {letter}({letter}|{decdigit}|\.)*
+string \'([^\']|\\\')*\'
+comment \/\/.*\n
+whitespace [ \t\r]+
+
+%%
+
+\{ {
+ return TOK_LBRACE;
+ }
+\} {
+ return TOK_RBRACE;
+ }
+\[ {
+ return TOK_LBRACKET;
+ }
+\] {
+ P(RBRACKET, AST_EX_SUBSCRIPT, "[ ]");
+ }
+\, {
+ return TOK_COMMA;
+ }
+\: {
+ P(COLON, AST_EX_FIELDSPEC, yytext);
+ }
+\; {
+ return TOK_SEMI;
+ }
+set {
+ P(SET, AST_ST_SET, yytext);
+ }
+get {
+ P(GET, AST_ST_GET, yytext);
+ }
+state {
+ P(STATE, AST_KW_STATE, yytext);
+ }
+{string} {
+ yytext[yyleng-1] = '\0';
+ P(STRING, AST_EX_STRING, yytext + 1);
+ }
+{offset} {
+ P(OFFSET, AST_EX_OFFSET, yytext);
+ }
+{number} {
+ P(NUMBER, AST_EX_NUMBER, yytext);
+ }
+{id} {
+ P(ID, AST_EX_ID, yytext);
+ }
+{comment} {
+ COLNUM = 0;
+ EXTRA->ls_linenum++;
+ }
+<<EOF>> {
+ return 0;
+ }
+\n {
+ COLNUM = 0;
+ EXTRA->ls_linenum++;
+ }
+{whitespace} ;
+. {
+ printf("Unexpected character '%s' on line %d column %d\n",
+ yytext, yylineno, COLNUM);
+ return 1;
+ }
+
+%%
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 74ee2d0..3045337 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -356,6 +356,10 @@ extern const unsigned lgfs2_ld_type_size;
extern const struct lgfs2_symbolic lgfs2_ld1_types[];
extern const unsigned lgfs2_ld1_type_size;
extern int lgfs2_selfcheck(void);
+extern const struct lgfs2_metadata *lgfs2_find_mtype(uint32_t mh_type, const unsigned versions);
+extern int lgfs2_field_print(const struct gfs2_buffer_head *bh,
+ const struct lgfs2_metadata *mtype,
+ const struct lgfs2_metafield *field);
/* bitmap.c */
struct gfs2_bmap {
@@ -379,6 +383,7 @@ extern struct gfs2_buffer_head *__bread(struct gfs2_sbd *sdp, uint64_t num,
int line, const char *caller);
extern int bwrite(struct gfs2_buffer_head *bh);
extern int brelse(struct gfs2_buffer_head *bh);
+extern uint32_t lgfs2_get_block_type(const struct gfs2_buffer_head *lbh);
#define bmodified(bh) do { bh->b_modified = 1; } while(0)
@@ -828,6 +833,25 @@ extern void gfs2_log_descriptor_print(struct gfs2_log_descriptor *ld);
extern void gfs2_statfs_change_print(struct gfs2_statfs_change *sc);
extern void gfs2_quota_change_print(struct gfs2_quota_change *qc);
+/* Language functions */
+
+struct lgfs2_lang_state;
+
+struct lgfs2_lang_result {
+ uint64_t lr_blocknr;
+ struct gfs2_buffer_head *lr_bh;
+ const struct lgfs2_metadata *lr_mtype;
+ int lr_state; // GFS2_BLKST_*
+};
+
+extern struct lgfs2_lang_state *lgfs2_lang_init(void);
+extern int lgfs2_lang_parsef(struct lgfs2_lang_state *state, FILE *script);
+extern int lgfs2_lang_parses(struct lgfs2_lang_state *state, const char *script);
+extern struct lgfs2_lang_result *lgfs2_lang_result_next(struct lgfs2_lang_state *state, struct gfs2_sbd *sbd);
+extern int lgfs2_lang_result_print(struct lgfs2_lang_result *result);
+extern void lgfs2_lang_result_free(struct lgfs2_lang_result **result);
+extern void lgfs2_lang_free(struct lgfs2_lang_state **state);
+
__END_DECLS
#endif /* __LIBGFS2_DOT_H__ */
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index a677cdc..29bf239 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -808,3 +808,53 @@ int lgfs2_selfcheck(void)
return ret;
}
+const struct lgfs2_metadata *lgfs2_find_mtype(uint32_t mh_type, const unsigned versions)
+{
+ const struct lgfs2_metadata *m = lgfs2_metadata;
+ unsigned n = 0;
+
+ do {
+ if ((m[n].versions & versions) && m[n].mh_type == mh_type)
+ return &m[n];
+ n++;
+ } while (n < lgfs2_metadata_size);
+
+ return NULL;
+}
+
+/**
+ * Print a representation of an arbitrary field of an arbitrary GFS2 block to stdout
+ * Returns 0 if successful, 1 otherwise
+ */
+int lgfs2_field_print(const struct gfs2_buffer_head *bh, const struct lgfs2_metadata *mtype,
+ const struct lgfs2_metafield *field)
+{
+ const char *fieldp = (char *)bh->iov.iov_base + field->offset;
+
+ printf("%s\t%"PRIu64"\t%u\t%u\t%s\t", mtype->name, bh->b_blocknr, field->offset, field->length, field->name);
+ if (field->flags & LGFS2_MFF_UUID) {
+ printf("'%s'\n", str_uuid((const unsigned char *)fieldp));
+ } else if (field->flags & LGFS2_MFF_STRING) {
+ printf("'%s'\n", fieldp);
+ } else {
+ switch(field->length) {
+ case 1:
+ printf("%"PRIu8"\n", *(uint8_t *)fieldp);
+ break;
+ case 2:
+ printf("%"PRIu16"\n", be16_to_cpu(*(uint16_t *)fieldp));
+ break;
+ case 4:
+ printf("%"PRIu32"\n", be32_to_cpu(*(uint32_t *)fieldp));
+ break;
+ case 8:
+ printf("%"PRIu64"\n", be64_to_cpu(*(uint64_t *)fieldp));
+ break;
+ default:
+ // "Reserved" field so just print 0
+ printf("0\n");
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/gfs2/libgfs2/misc.c b/gfs2/libgfs2/misc.c
index a68da4a..c2eb245 100644
--- a/gfs2/libgfs2/misc.c
+++ b/gfs2/libgfs2/misc.c
@@ -26,8 +26,6 @@
#define SYS_BASE "/sys/fs/gfs2" /* FIXME: Look in /proc/mounts to find this */
#define DIV_RU(x, y) (((x) + (y) - 1) / (y))
-static char sysfs_buf[PAGE_SIZE];
-
int compute_heightsize(struct gfs2_sbd *sdp, uint64_t *heightsize,
uint32_t *maxheight, uint32_t bsize1, int diptrs, int inptrs)
{
diff --git a/gfs2/libgfs2/parser.y b/gfs2/libgfs2/parser.y
new file mode 100644
index 0000000..084d15e
--- /dev/null
+++ b/gfs2/libgfs2/parser.y
@@ -0,0 +1,186 @@
+%code top {
+#include <errno.h>
+#include "lang.h"
+#include "lexer.h"
+
+static int yyerror(struct lgfs2_lang_state *state, yyscan_t lexer, const char *errorstr)
+{
+ fprintf(stderr, "%d:%d: %s\n", state->ls_linenum, state->ls_colnum, errorstr);
+ return 1;
+}
+
+}
+%defines
+%debug
+%define api.pure
+%parse-param { struct lgfs2_lang_state *state }
+%parse-param { yyscan_t lexer }
+%lex-param { yyscan_t lexer }
+%start script
+%token TOK_COLON
+%token TOK_COMMA
+%token TOK_ID
+%token TOK_LBRACE
+%token TOK_LBRACKET
+%token TOK_NUMBER
+%token TOK_OFFSET
+%token TOK_RBRACE
+%token TOK_RBRACKET
+%token TOK_SEMI
+%token TOK_SET
+%token TOK_GET
+%token TOK_STATE
+%token TOK_STRING
+%%
+script: statements {
+ state->ls_ast_root = $1;
+ state->ls_interp_curr = $1;
+ }
+ | statements TOK_SEMI {
+ state->ls_ast_root = $1;
+ state->ls_interp_curr = $1;
+ }
+;
+statements: statements TOK_SEMI statement {
+ state->ls_ast_tail->ast_left = $3;
+ state->ls_ast_tail = $3;
+ $$ = $1;
+ }
+ | statement {
+ if (state->ls_ast_tail == NULL)
+ state->ls_ast_tail = $1;
+ $$ = $1;
+ }
+;
+
+statement: set_stmt { $$ = $1; }
+ | get_stmt { $$ = $1; }
+;
+set_stmt: TOK_SET blockspec structspec {
+ $1->ast_right = $2;
+ $2->ast_right = $3;
+ $$ = $1;
+ }
+;
+get_stmt: TOK_GET blockspec { $1->ast_right = $2; $$ = $1; }
+ | TOK_GET blockspec TOK_STATE {
+ $1->ast_right = $2;
+ $2->ast_right = $3;
+ $$ = $1;
+ }
+;
+blockspec: offset { $$ = $1; }
+ | address { $$ = $1; }
+ | path { $$ = $1; }
+ | block_literal { $$ = $1; }
+ | subscript { $$ = $1; }
+;
+offset: blockspec TOK_OFFSET {
+ $2->ast_left = $1;
+ $$ = $2;
+ }
+;
+block_literal: identifier { $$ = $1; }
+;
+subscript: block_literal TOK_LBRACKET index TOK_RBRACKET {
+ $4->ast_left = $1;
+ $1->ast_left = $3;
+ $$ = $4;
+ }
+;
+index: number { $$ = $1; }
+ | identifier { $$ = $1; }
+;
+address: number { $1->ast_type = AST_EX_ADDRESS; $$ = $1; }
+;
+path: string {
+ if (*($1->ast_str) != '/') {
+ fprintf(stderr, "Path doesn't begin with '/': %s\n", $1->ast_str);
+ YYABORT;
+ }
+ $1->ast_type = AST_EX_PATH;
+ $$ = $1;
+ }
+;
+structspec: TOK_LBRACE fieldspecs TOK_RBRACE { $$ = $2; }
+;
+fieldspecs: fieldspecs TOK_COMMA fieldspec { $1->ast_left = $3; $$ = $1; }
+ | fieldspec { $$ = $1; }
+;
+fieldspec: identifier TOK_COLON fieldvalue {
+ $2->ast_right = $1;
+ $1->ast_right = $3;
+ $$ = $2;
+ }
+;
+fieldvalue: number { $$ = $1; }
+ | string { $$ = $1; }
+;
+number: TOK_NUMBER { $$ = $1; }
+string: TOK_STRING { $$ = $1; }
+identifier: TOK_ID { $$ = $1; }
+%%
+
+/**
+ * Allocate and initialize a new parse state structure. The caller must free the
+ * memory returned by this function.
+ */
+struct lgfs2_lang_state *lgfs2_lang_init(void)
+{
+ struct lgfs2_lang_state *state;
+ state = calloc(1, sizeof(struct lgfs2_lang_state));
+ if (state == NULL) {
+ return NULL;
+ }
+ state->ls_linenum = 1;
+ return state;
+}
+
+void lgfs2_lang_free(struct lgfs2_lang_state **state)
+{
+ ast_destroy(&(*state)->ls_ast_root);
+ free(*state);
+ *state = NULL;
+}
+
+int lgfs2_lang_parsef(struct lgfs2_lang_state *state, FILE *src)
+{
+ int ret = 0;
+ yyscan_t lexer;
+
+ ret = yylex_init_extra(state, &lexer);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to initialize lexer.\n");
+ return ret;
+ }
+
+ yyset_in(src, lexer);
+ ret = yyparse(state, lexer);
+ yylex_destroy(lexer);
+ return ret;
+}
+
+int lgfs2_lang_parses(struct lgfs2_lang_state *state, const char *cstr)
+{
+ int ret;
+ FILE *src;
+ char *str = strdup(cstr);
+
+ if (str == NULL) {
+ perror("Failed to duplicate source string");
+ return 1;
+ }
+ src = fmemopen(str, strlen(str), "r");
+ if (src == NULL) {
+ perror("Failed to open string as source file");
+ free(str);
+ return 1;
+ }
+ ret = lgfs2_lang_parsef(state, src);
+ fclose(src);
+ free(str);
+ if (ret != 0 || state->ls_errnum != 0) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
index a3c1964..fdf0e60 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -25,7 +25,7 @@ int check_sb(struct gfs2_sb *sb)
{
if (sb->sb_header.mh_magic != GFS2_MAGIC ||
sb->sb_header.mh_type != GFS2_METATYPE_SB) {
- errno = -EIO;
+ errno = EIO;
return -1;
}
if (sb->sb_fs_format == GFS_FORMAT_FS &&
11 years, 6 months
cluster: STABLE32 - rgmanager: Randomize node list when relocating with no target
by Ryan McCabe
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=db3b4f9b78d...
Commit: db3b4f9b78de7f90e2e19c590b14e5f3ec57333e
Parent: a844e71abe9da79e7b6830449e3f5d5d8fed1224
Author: Ryan McCabe <rmccabe(a)redhat.com>
AuthorDate: Mon Oct 15 09:32:18 2012 -0400
Committer: Ryan McCabe <rmccabe(a)redhat.com>
CommitterDate: Mon Oct 15 09:44:46 2012 -0400
rgmanager: Randomize node list when relocating with no target
Randomize the node list when choosing a node to which to forward
a start request to when relocating a service with no specified
target. The current behavior causes the service to bounce between
the two nodes with the highest node IDs when relocating in a loop.
Resolves: rhbz#831648
Acked-by: Fabio M. Di Nitto <fdinitto(a)redhat.com>
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
---
rgmanager/include/members.h | 1 +
rgmanager/src/clulib/members.c | 20 ++++++++++++++++++++
rgmanager/src/daemons/rg_state.c | 1 +
3 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/rgmanager/include/members.h b/rgmanager/include/members.h
index 7e99e17..09f7a9a 100644
--- a/rgmanager/include/members.h
+++ b/rgmanager/include/members.h
@@ -27,6 +27,7 @@ char * memb_id_to_name(cluster_member_list_t *ml, int nodeid);
cman_node_t * memb_id_to_p(cluster_member_list_t *ml, int nodeid);
cman_node_t * memb_name_to_p(cluster_member_list_t *ml, char *name);
void free_member_list(cluster_member_list_t *ml);
+void member_list_shuffle(cluster_member_list_t *ml);
cluster_member_list_t *memb_gained(cluster_member_list_t *old,
cluster_member_list_t *new);
cluster_member_list_t *memb_lost(cluster_member_list_t *old,
diff --git a/rgmanager/src/clulib/members.c b/rgmanager/src/clulib/members.c
index e6475e1..8a98f98 100644
--- a/rgmanager/src/clulib/members.c
+++ b/rgmanager/src/clulib/members.c
@@ -11,6 +11,7 @@
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <rg_types.h>
#include <pthread.h>
#include <errno.h>
@@ -505,3 +506,22 @@ member_list_dup(cluster_member_list_t *orig)
return ret;
}
+void member_list_shuffle(cluster_member_list_t *ml) {
+ int i;
+ unsigned st;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ st = (int)(tv.tv_usec);
+
+
+ for (i = 0 ; i < ml->cml_count ; i++) {
+ cman_node_t temp;
+ int newidx = rand_r(&st) % ml->cml_count;
+ if (newidx == i)
+ continue;
+ memcpy(&temp, &ml->cml_members[i], sizeof(cman_node_t));
+ memcpy(&ml->cml_members[i], &ml->cml_members[newidx], sizeof(cman_node_t));
+ memcpy(&ml->cml_members[newidx], &temp, sizeof(cman_node_t));
+ }
+}
diff --git a/rgmanager/src/daemons/rg_state.c b/rgmanager/src/daemons/rg_state.c
index 9f0c68e..765c3eb 100644
--- a/rgmanager/src/daemons/rg_state.c
+++ b/rgmanager/src/daemons/rg_state.c
@@ -1938,6 +1938,7 @@ handle_relocate_req(char *svcName, int orig_request, int preferred_target,
allowed_nodes = member_list();
//count_resource_groups(allowed_nodes);
}
+ member_list_shuffle(allowed_nodes);
if (preferred_target > 0)
memb_mark_down(allowed_nodes, preferred_target);
11 years, 6 months
cluster: RHEL6 - rgmanager: Randomize node list when relocating with no target
by Ryan McCabe
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=13dcbb8265e...
Commit: 13dcbb8265eafcdf69c033f45f2a37aa44b18908
Parent: a4d6a6aa6ba6bd8d610d42fdb518089efa4112ee
Author: Ryan McCabe <rmccabe(a)redhat.com>
AuthorDate: Mon Oct 15 09:32:18 2012 -0400
Committer: Ryan McCabe <rmccabe(a)redhat.com>
CommitterDate: Mon Oct 15 09:38:04 2012 -0400
rgmanager: Randomize node list when relocating with no target
Randomize the node list when choosing a node to which to forward
a start request to when relocating a service with no specified
target. The current behavior causes the service to bounce between
the two nodes with the highest node IDs when relocating in a loop.
Resolves: rhbz#831648
Acked-by: Fabio M. Di Nitto <fdinitto(a)redhat.com>
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
---
rgmanager/include/members.h | 1 +
rgmanager/src/clulib/members.c | 20 ++++++++++++++++++++
rgmanager/src/daemons/rg_state.c | 1 +
3 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/rgmanager/include/members.h b/rgmanager/include/members.h
index 7e99e17..09f7a9a 100644
--- a/rgmanager/include/members.h
+++ b/rgmanager/include/members.h
@@ -27,6 +27,7 @@ char * memb_id_to_name(cluster_member_list_t *ml, int nodeid);
cman_node_t * memb_id_to_p(cluster_member_list_t *ml, int nodeid);
cman_node_t * memb_name_to_p(cluster_member_list_t *ml, char *name);
void free_member_list(cluster_member_list_t *ml);
+void member_list_shuffle(cluster_member_list_t *ml);
cluster_member_list_t *memb_gained(cluster_member_list_t *old,
cluster_member_list_t *new);
cluster_member_list_t *memb_lost(cluster_member_list_t *old,
diff --git a/rgmanager/src/clulib/members.c b/rgmanager/src/clulib/members.c
index 5f98708..715fe39 100644
--- a/rgmanager/src/clulib/members.c
+++ b/rgmanager/src/clulib/members.c
@@ -11,6 +11,7 @@
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <rg_types.h>
#include <pthread.h>
#include <errno.h>
@@ -501,3 +502,22 @@ member_list_dup(cluster_member_list_t *orig)
return ret;
}
+void member_list_shuffle(cluster_member_list_t *ml) {
+ int i;
+ unsigned st;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ st = (int)(tv.tv_usec);
+
+
+ for (i = 0 ; i < ml->cml_count ; i++) {
+ cman_node_t temp;
+ int newidx = rand_r(&st) % ml->cml_count;
+ if (newidx == i)
+ continue;
+ memcpy(&temp, &ml->cml_members[i], sizeof(cman_node_t));
+ memcpy(&ml->cml_members[i], &ml->cml_members[newidx], sizeof(cman_node_t));
+ memcpy(&ml->cml_members[newidx], &temp, sizeof(cman_node_t));
+ }
+}
diff --git a/rgmanager/src/daemons/rg_state.c b/rgmanager/src/daemons/rg_state.c
index 80e8667..59454bf 100644
--- a/rgmanager/src/daemons/rg_state.c
+++ b/rgmanager/src/daemons/rg_state.c
@@ -1924,6 +1924,7 @@ handle_relocate_req(char *svcName, int orig_request, int preferred_target,
allowed_nodes = member_list();
//count_resource_groups(allowed_nodes);
}
+ member_list_shuffle(allowed_nodes);
if (preferred_target > 0)
memb_mark_down(allowed_nodes, preferred_target);
11 years, 6 months
cluster: RHEL6 - rgmanager: Fix return code when a service would deadlock
by Ryan McCabe
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=a4d6a6aa6ba...
Commit: a4d6a6aa6ba6bd8d610d42fdb518089efa4112ee
Parent: 8f339d0e5c151c6e444c0108b98a8c3b63fd28b8
Author: Ryan McCabe <rmccabe(a)redhat.com>
AuthorDate: Fri Oct 12 21:14:19 2012 -0400
Committer: Ryan McCabe <rmccabe(a)redhat.com>
CommitterDate: Mon Oct 15 09:38:04 2012 -0400
rgmanager: Fix return code when a service would deadlock
When we detect that starting a service would cause a deadlock, return 0
instead of -1. This fixes a crash that occurred when -1 was returned.
Resolves: rhbz#861157
Acked-by: Fabio M. Di Nitto <fdinitto(a)redhat.com>
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
---
rgmanager/src/daemons/rg_thread.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/rgmanager/src/daemons/rg_thread.c b/rgmanager/src/daemons/rg_thread.c
index 5e551c3..b888717 100644
--- a/rgmanager/src/daemons/rg_thread.c
+++ b/rgmanager/src/daemons/rg_thread.c
@@ -756,7 +756,7 @@ rt_enqueue_request(const char *resgroupname, int request,
logt_print(LOG_DEBUG,
"Failed to queue %d request for %s: Would block\n",
request, resgroupname);
- return -1;
+ return 0;
}
ret = rq_queue_request(resgroup->rt_queue, resgroup->rt_name,
11 years, 6 months
cluster: RHEL6 - mkfs.gfs2: Check locktable more strictly for valid chars
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=8f339d0e5c1...
Commit: 8f339d0e5c151c6e444c0108b98a8c3b63fd28b8
Parent: b257ab953eaa3acc20fbdd47c34579fa0282d737
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri Oct 12 15:48:08 2012 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Mon Oct 15 12:22:20 2012 +0100
mkfs.gfs2: Check locktable more strictly for valid chars
Previously mkfs.gfs2 allowed any printable characters to be used in the
locktable name. This causes problems when the locktable contains special
characters such as '/'. This patch limits the locktable to alphanumeric
characters plus hyphens and underscores.
Resolves: rhbz#862847
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/man/mkfs.gfs2.8 | 3 ++-
gfs2/mkfs/main_mkfs.c | 6 ++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/gfs2/man/mkfs.gfs2.8 b/gfs2/man/mkfs.gfs2.8
index 63348f8..c83b432 100644
--- a/gfs2/man/mkfs.gfs2.8
+++ b/gfs2/man/mkfs.gfs2.8
@@ -73,7 +73,8 @@ Clustername must match that in cluster.conf; only members of this
cluster are permitted to use this file system.
Fsname is a unique file system name used to distinguish this GFS2 file
system from others created (1 to 16 characters). Lock_nolock doesn't
-use this field.
+use this field. Valid \fIclustername\fRs and \fIfsname\fRs may only contain
+alphanumeric characters, hyphens (-) and underscores (_).
.TP
\fB-u\fP \fIMegaBytes\fR
Initial size of each journal's unlinked tag file
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index bcc60e4..7163cf1 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -263,10 +263,8 @@ static void test_locking(char *lockproto, char *locktable)
exit(-1);
}
for (c = locktable; *c; c++) {
- if (isspace(*c))
- die( _("locktable error: contains space characters\n"));
- if (!isprint(*c))
- die( _("locktable error: contains unprintable characters\n"));
+ if (!isalnum(*c) && (*c != '-') && (*c != '_') && (*c != ':'))
+ die( _("locktable error: invalid character '%c'\n"), *c);
}
c = strstr(locktable, ":");
11 years, 6 months
gfs2-utils: master - mkfs.gfs2: Check locktable more strictly for valid chars
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=24fad71d...
Commit: 24fad71d36ecce70a5d0d4206d0b13e7b77ec94c
Parent: abe3d4b88afe39d839692865b29bd800f09cba8a
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri Oct 12 01:36:32 2012 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Oct 12 01:36:32 2012 +0100
mkfs.gfs2: Check locktable more strictly for valid chars
Previously mkfs.gfs2 allowed any printable characters to be used in the
locktable name. This causes problems when the locktable contains special
characters such as '/'. This patch limits the locktable to alphanumeric
characters plus hyphens and underscores.
Ref: bz#862847
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/man/mkfs.gfs2.8 | 3 ++-
gfs2/mkfs/main_mkfs.c | 6 ++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/gfs2/man/mkfs.gfs2.8 b/gfs2/man/mkfs.gfs2.8
index d17e272..4613305 100644
--- a/gfs2/man/mkfs.gfs2.8
+++ b/gfs2/man/mkfs.gfs2.8
@@ -73,7 +73,8 @@ Clustername must match that in cluster.conf; only members of this
cluster are permitted to use this file system.
Fsname is a unique file system name used to distinguish this GFS2 file
system from others created (1 to 16 characters). Lock_nolock doesn't
-use this field.
+use this field. Valid \fIclustername\fRs and \fIfsname\fRs may only contain
+alphanumeric characters, hyphens (-) and underscores (_).
.TP
\fB-V\fP
Print program version information, then exit.
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index 2d529d7..3bbb5b4 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -259,10 +259,8 @@ static void test_locking(char *lockproto, char *locktable)
exit(-1);
}
for (c = locktable; *c; c++) {
- if (isspace(*c))
- die( _("locktable error: contains space characters\n"));
- if (!isprint(*c))
- die( _("locktable error: contains unprintable characters\n"));
+ if (!isalnum(*c) && (*c != '-') && (*c != '_') && (*c != ':'))
+ die( _("locktable error: invalid character '%c'\n"), *c);
}
c = strstr(locktable, ":");
11 years, 6 months
cluster: STABLE32 - rgmanager: Fix return code when a service would deadlock
by Ryan McCabe
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=a844e71abe9...
Commit: a844e71abe9da79e7b6830449e3f5d5d8fed1224
Parent: cdd37c317a1b0ebfb4daaf56f5a6beac20356792
Author: Ryan McCabe <rmccabe(a)redhat.com>
AuthorDate: Fri Oct 12 21:14:19 2012 -0400
Committer: Ryan McCabe <rmccabe(a)redhat.com>
CommitterDate: Fri Oct 12 21:14:19 2012 -0400
rgmanager: Fix return code when a service would deadlock
When we detect that starting a service would cause a deadlock, return 0
instead of -1. This fixes a crash that occurred when -1 was returned.
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
---
rgmanager/src/daemons/rg_thread.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/rgmanager/src/daemons/rg_thread.c b/rgmanager/src/daemons/rg_thread.c
index 31f289c..4f46c25 100644
--- a/rgmanager/src/daemons/rg_thread.c
+++ b/rgmanager/src/daemons/rg_thread.c
@@ -759,7 +759,7 @@ rt_enqueue_request(const char *resgroupname, int request,
logt_print(LOG_DEBUG,
"Failed to queue %d request for %s: Would block\n",
request, resgroupname);
- return -1;
+ return 0;
}
ret = rq_queue_request(resgroup->rt_queue, resgroup->rt_name,
11 years, 6 months