gfs_controld: Allow mounts entirely via sysfs/uevent interface
This patch adds the ability for gfs_controld to optionally allow
mounts via sysfs/uevents rather than requiring the mount.gfs2
helper. Some kernel support is required to do that, and the support
is in recent kernels (2.6.36 and up) so this has to be backwards
compatible.
The other change is that when a withdraw occurs, the device is now
specified by device number. This number is obtained from sysfs
and avoids the issue which would otherwise occur with the new
mount sequence for which the device path is not available.
There is a flag added to the mount group which determines whether
the mount helper exists or not. The flag is set depending on
whether the first notification of the filesystem is from the
ADD uevent or from the mount helper.
The plan is that the mount helper will be gradually phased out
over time.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
diff --git a/group/gfs_controld/cpg-new.c b/group/gfs_controld/cpg-new.c
index 23b7a86..a72d0f1 100644
--- a/group/gfs_controld/cpg-new.c
+++ b/group/gfs_controld/cpg-new.c
@@ -261,7 +261,6 @@ static int daemon_member_count;
/* start message from all nodes shows zero started_count */
@@ -2769,7 +2768,7 @@ int gfs_join_mountgroup(struct mountgroup *mg)
order. We can just ignore the second. The second would either not find
the mg here, or would see mg->leaving of 1 from the first. */
static void receive_withdraw_ack(struct gfs_header *hd, int len)
diff --git a/group/gfs_controld/gfs_daemon.h b/group/gfs_controld/gfs_daemon.h
index fdfc603..d5ea341 100644
--- a/group/gfs_controld/gfs_daemon.h
+++ b/group/gfs_controld/gfs_daemon.h
@@ -126,12 +126,12 @@ struct mountgroup {
int our_jid;
int spectator;
int ro;
- int rw;
int joining;
int leaving;
int kernel_mount_error;
int kernel_mount_done;
int first_mounter;
+ int no_mount_helper;
/* cpg-new stuff */
@@ -181,7 +181,7 @@ void process_mountgroups(void);
int gfs_join_mountgroup(struct mountgroup *mg);
void do_leave(struct mountgroup *mg, int mnterr);
void gfs_mount_done(struct mountgroup *mg);
-void send_remount(struct mountgroup *mg, struct gfsc_mount_args *ma);
+void send_remount(struct mountgroup *mg, int ro);
void send_withdraw(struct mountgroup *mg);
int set_mountgroup_info(struct mountgroup *mg, struct gfsc_mountgroup *out);
int set_node_info(struct mountgroup *mg, int nodeid, struct gfsc_node *node);
@@ -191,6 +191,7 @@ int set_mountgroup_nodes(struct mountgroup *mg, int option, int *node_count,
void free_mg(struct mountgroup *mg);
void node_history_cluster_add(int nodeid);
void node_history_cluster_remove(int nodeid);
+void gfs_leave_mountgroup(struct mountgroup *mg, int mnterr);
+/*
+ * This is called only if mount.gfs2 has not already set up the
+ * mount group. In that case we know that the mount helper doesn't
+ * exist and thus the no_mount_helper flag is set, to indicate that
+ * this mount will be administrated entirely via the uevent/sysfs
+ * interface.
+ */
+
+static void do_new_mount(const char *name, struct mountgroup *mg,
+ const char *uevent_vals[])
+{
+ int rv;
+
+ if (!uevent_vars[Env_LOCKPROTO] ||
+ !uevent_vars[Env_LOCKTABLE])
+ return;
+
+ /* We only care about lock_dlm mounts */
+ if (strcmp(uevent_vals[Env_LOCKPROTO], "lock_dlm") != 0)
+ return;
+
+ if (mg) {
+ /* Might have already been set up by mount.gfs2 */
+ if (mg->no_mount_helper == 0)
+ return;
+ log_error("do_new_mount: duplicate mount %s",
+ uevent_vals[Env_LOCKTABLE]);
+ return;
+ }
+
+ mg = create_mg(name);
+ if (mg == NULL)
+ return;
+
+ mg->no_mount_helper = 1;
+
+ strncpy(mg->mount_args.type, uevent_vals[Env_SUBSYSTEM], PATH_MAX);
+ strncpy(mg->mount_args.proto, uevent_vals[Env_LOCKPROTO], PATH_MAX);
+ strncpy(mg->mount_args.table, uevent_vals[Env_LOCKTABLE], PATH_MAX);
+
+ if (uevent_vals[Env_SPECTATOR] &&
+ strcmp(uevent_vals[Env_SPECTATOR], "1") == 0)
+ mg->spectator = 1;
+
+ if (uevent_vals[Env_RDONLY] &&
+ strcmp(uevent_vals[Env_RDONLY], "1") == 0)
+ mg->ro = 1;
+
+ list_add(&mg->list, &mountgroups);
+ rv = gfs_join_mountgroup(mg);
+ if (rv) {
+ log_error("join: group join error %d", rv);
+ goto fail;
+ }
+ log_group(mg, "do_new_mount ci %d result %d first=%d:jid=%d",
+ mg->mount_client, rv, mg->first_mounter, mg->our_jid);
+ return;
+
+fail:
+ list_del(&mg->list);
+ free(mg);
+ return;
+}
+
+/*
+ * This is called upon successful mount and also upon a successful
+ * remount operation. Unless the no_mount_helper flag is set on the
+ * mount group, this is a no-op.
+ */
+static void do_online(struct mountgroup *mg, const char *uevent_vals[])
+{
+ int ro = 0;
+
+ /* If using mount helper, ignore the message here */
+ if (mg->no_mount_helper == 0)
+ return;
+
+ /* Catch successful original mount */
+ if (!mg->kernel_mount_done) {
+ mg->mount_client = 0;
+ mg->kernel_mount_done = 1;
+ mg->kernel_mount_error = 0;
+ gfs_mount_done(mg);
+ return;
+ }
+
+ /* From here on, its remounts only */
+
+ if (uevent_vals[Env_RDONLY] &&
+ strcmp(uevent_vals[Env_RDONLY], "1") == 0)
+ ro = 1;
+
+ send_remount(mg, ro);
+}
+
static void process_uevent(int ci)
{
struct mountgroup *mg;
@@ -302,6 +411,12 @@ static void process_uevent(int ci)
}
mg = find_mg(fsname);
+
+ if (!strcmp(uevent_vals[Env_ACTION], "add")) {
+ do_new_mount(fsname, mg, uevent_vals);
+ return;
+ }
+
if (!mg) {
log_error("mount group %s not found", fsname);
return;
@@ -314,6 +429,16 @@ static void process_uevent(int ci)