[Cluster-devel] cluster/group/gfs_controld lock_dlm.h main.c r ...
teigland at sourceware.org
teigland at sourceware.org
Wed Dec 20 19:13:14 UTC 2006
CVSROOT: /cvs/cluster
Module name: cluster
Changes by: teigland at sourceware.org 2006-12-20 19:13:13
Modified files:
group/gfs_controld: lock_dlm.h main.c recover.c
Log message:
Support mounting a single fs on multiple mount points.
bz 218560
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/group/gfs_controld/lock_dlm.h.diff?cvsroot=cluster&r1=1.26&r2=1.27
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/group/gfs_controld/main.c.diff?cvsroot=cluster&r1=1.27&r2=1.28
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/group/gfs_controld/recover.c.diff?cvsroot=cluster&r1=1.27&r2=1.28
--- cluster/group/gfs_controld/lock_dlm.h 2006/12/19 17:05:59 1.26
+++ cluster/group/gfs_controld/lock_dlm.h 2006/12/20 19:13:13 1.27
@@ -113,6 +113,12 @@
} \
}
+struct mountpoint {
+ struct list_head list;
+ char dir[PATH_MAX+1];
+ int client;
+};
+
struct mountgroup {
struct list_head list;
uint32_t id;
@@ -120,11 +126,11 @@
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 dir[PATH_MAX+1];
char options[MAX_OPTIONS_LEN+1];
char dev[PATH_MAX+1];
@@ -280,7 +286,7 @@
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);
+void got_mount_result(struct mountgroup *mg, int result, int ci, int another);
int client_send(int ci, char *buf, int len);
--- cluster/group/gfs_controld/main.c 2006/12/05 22:19:17 1.27
+++ cluster/group/gfs_controld/main.c 2006/12/20 19:13:13 1.28
@@ -21,6 +21,7 @@
int fd;
char type[32];
struct mountgroup *mg;
+ int another_mount;
};
static int client_maxi;
@@ -298,14 +299,15 @@
argv[6], &mg);
fd = client[ci].fd;
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
- if (!rv) {
+ 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]));
-
+ 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;
--- cluster/group/gfs_controld/recover.c 2006/12/19 22:19:01 1.27
+++ cluster/group/gfs_controld/recover.c 2006/12/20 19:13:13 1.28
@@ -1430,23 +1430,36 @@
}
}
-struct mountgroup *create_mg(char *name)
+struct mountgroup *create_mg(char *name, char *dir)
{
struct mountgroup *mg;
+ struct mountpoint *mp;
mg = malloc(sizeof(struct mountgroup));
+ if (!mg)
+ return NULL;
memset(mg, 0, sizeof(struct mountgroup));
INIT_LIST_HEAD(&mg->members);
INIT_LIST_HEAD(&mg->members_gone);
INIT_LIST_HEAD(&mg->resources);
INIT_LIST_HEAD(&mg->saved_messages);
+ INIT_LIST_HEAD(&mg->mountpoints);
mg->init = 1;
mg->master_nodeid = -1;
mg->low_nodeid = -1;
strncpy(mg->name, name, MAXNAME);
+ mp = malloc(sizeof(struct mountpoint));
+ if (!mp) {
+ free(mg);
+ return NULL;
+ }
+ memset(mp, 0, sizeof(struct mountpoint));
+ strncpy(mp->dir, dir, sizeof(mp->dir));
+ list_add(&mp->list, &mg->mountpoints);
+
return mg;
}
@@ -1473,12 +1486,23 @@
return NULL;
}
+struct mountpoint *find_mountpoint(struct mountgroup *mg, char *dir)
+{
+ struct mountpoint *mp;
+
+ list_for_each_entry(mp, &mg->mountpoints, list) {
+ if (!strcmp(mp->dir, dir))
+ return mp;
+ }
+ return NULL;
+}
+
struct mountgroup *find_mg_dir(char *dir)
{
struct mountgroup *mg;
list_for_each_entry(mg, &mounts, list) {
- if (!strcmp(mg->dir, dir))
+ if (find_mountpoint(mg, dir))
return mg;
}
return NULL;
@@ -1501,10 +1525,54 @@
return 0;
}
+int add_another_mountpoint(struct mountgroup *mg, char *dir, char *dev, int ci)
+{
+ struct mountpoint *mp;
+
+ log_group(mg, "add_another_mountpoint dir %s dev %s ci %d",
+ dir, dev, ci);
+
+ /* check if this is the same fs mounted on another dir or a different
+ fs with the same name (which is an error) */
+
+ if (strcmp(mg->dev, dev)) {
+ log_group(mg, "different fs dev %s with same name", mg->dev);
+ return -EINVAL;
+ }
+
+ if (find_mountpoint(mg, dir)) {
+ log_group(mg, "mount point %s already used", dir);
+ return -EBUSY;
+ }
+
+ /* we only really need to check one of these */
+ if (mg->mount_client || mg->mount_client_fd || !mg->kernel_mount_done) {
+ log_group(mg, "other mount in progress client %d fd %d done %d",
+ mg->mount_client, mg->mount_client_fd,
+ mg->kernel_mount_done);
+ return -EBUSY;
+ }
+
+ mp = malloc(sizeof(struct mountpoint));
+ if (!mp)
+ return -ENOMEM;
+
+ memset(mp, 0, sizeof(struct mountpoint));
+ strncpy(mp->dir, dir, sizeof(mp->dir));
+ list_add(&mp->list, &mg->mountpoints);
+ mg->mount_client = ci;
+
+ /* we return this special error to mount.gfs which mount.gfs will
+ recognize as meaning the fs is already mounted, so it shouldn't
+ read any hostdata from us, but just go ahead and mount(2) */
+
+ return -EALREADY;
+}
+
int do_mount(int ci, char *dir, char *type, char *proto, char *table,
char *options, char *dev, struct mountgroup **mg_ret)
{
- struct mountgroup *mg;
+ struct mountgroup *mg = NULL;
char table2[MAXLINE];
char *cluster = NULL, *name = NULL;
int rv;
@@ -1515,7 +1583,7 @@
if (strcmp(proto, "lock_dlm")) {
log_error("mount: lockproto %s not supported", proto);
rv = -EINVAL;
- goto fail;
+ goto out;
}
if (strstr(options, "jid=") ||
@@ -1523,7 +1591,7 @@
strstr(options, "id=")) {
log_error("mount: jid, first and id are reserved options");
rv = -EINVAL;
- goto fail;
+ goto out;
}
/* table is <cluster>:<name> */
@@ -1534,7 +1602,7 @@
name = strstr(table2, ":");
if (!name) {
rv = -EINVAL;
- goto fail;
+ goto out;
}
*name = '\0';
@@ -1543,23 +1611,22 @@
if (strlen(name) > MAXNAME) {
rv = -ENAMETOOLONG;
- goto fail;
+ goto out;
}
mg = find_mg(name);
if (mg) {
- rv = -EEXIST;
- goto fail;
+ rv = add_another_mountpoint(mg, dir, dev, ci);
+ goto out;
}
- mg = create_mg(name);
+ mg = create_mg(name, dir);
if (!mg) {
rv = -ENOMEM;
- goto fail;
+ goto out;
}
mg->mount_client = ci;
- strncpy(mg->dir, dir, sizeof(mg->dir));
strncpy(mg->type, type, sizeof(mg->type));
strncpy(mg->table, table, sizeof(mg->table));
strncpy(mg->options, options, sizeof(mg->options));
@@ -1570,7 +1637,7 @@
rv = -1;
log_error("mount: fs requires cluster=\"%s\" current=\"%s\"",
cluster, clustername);
- goto fail;
+ goto out;
} else
log_group(mg, "cluster name matches: %s", clustername);
@@ -1581,7 +1648,7 @@
if (!we_are_in_fence_domain()) {
rv = -EINVAL;
log_error("mount: not in default fence domain");
- goto fail;
+ goto out;
}
}
@@ -1591,7 +1658,7 @@
if (mg->spectator) {
rv = -EINVAL;
log_error("mount: readonly invalid with spectator");
- goto fail;
+ goto out;
}
mg->readonly = 1;
}
@@ -1599,17 +1666,15 @@
if (strlen(options) > MAX_OPTIONS_LEN-1) {
rv = -EINVAL;
log_error("mount: options too long %d", strlen(options));
- goto fail;
+ goto out;
}
list_add(&mg->list, &mounts);
- *mg_ret = mg;
-
group_join(gh, name);
- return 0;
-
- fail:
- log_error("mount: failed %d", rv);
+ rv = 0;
+ out:
+ *mg_ret = mg;
+ log_group(mg, "do_mount: rv %d", rv);
return rv;
}
@@ -1891,14 +1956,20 @@
int do_unmount(int ci, char *dir, int mnterr)
{
struct mountgroup *mg;
+ struct mountpoint *mp;
list_for_each_entry(mg, &withdrawn_mounts, list) {
- if (!strcmp(mg->dir, dir)) {
- log_group(mg, "unmount withdrawn fs");
+ mp = find_mountpoint(mg, dir);
+ if (!mp)
+ continue;
+ log_group(mg, "unmount %s for withdrawn fs", dir);
+ list_del(&mp->list);
+ free(mp);
+ if (list_empty(&mg->mountpoints)) {
list_del(&mg->list);
free(mg);
- return 0;
}
+ return 0;
}
mg = find_mg_dir(dir);
@@ -1922,10 +1993,27 @@
}
if (mg->withdraw) {
- log_error("do_unmount: fs on %s is withdrawing", dir);
+ log_error("%s do_unmount: fs on %s is withdrawing",
+ mg->name, dir);
+ return -1;
+ }
+
+ if (!mg->kernel_mount_done) {
+ log_error("%s do_unmount: fs on %s is still mounting",
+ mg->name, dir);
return -1;
}
+ mp = find_mountpoint(mg, dir);
+ ASSERT(mp);
+ list_del(&mp->list);
+ free(mp);
+
+ if (!list_empty(&mg->mountpoints)) {
+ log_group(mg, "removed mountpoint %s, more remaining", dir);
+ return 0;
+ }
+
/* Check to see if we're waiting for a kernel recovery_done to do a
start_done(). If so, call the start_done() here because we won't be
getting anything else from gfs-kernel which is now gone. */
@@ -1934,6 +2022,7 @@
log_group(mg, "do_unmount: fill in start_done");
start_done(mg);
}
+
out:
group_leave(gh, mg->name);
return 0;
@@ -1972,8 +2061,6 @@
if (rv < 0)
log_error("notify_mount_client: send failed %d", rv);
- mg->mount_client = 0;
-
if (error) {
log_group(mg, "leaving due to mount error: %s", mg->error_msg);
if (memb->finished)
@@ -2003,14 +2090,42 @@
log_group(mg, "ping_kernel_mount %d", rv);
}
-void got_mount_result(struct mountgroup *mg, int result)
+/* remove the mountpoint that this client added */
+void remove_failed_mountpoint(struct mountgroup *mg, int ci)
+{
+ struct mountpoint *mp;
+ int found = 0;
+
+ list_for_each_entry(mp, &mg->mountpoints, list) {
+ if (mp->client == ci) {
+ list_del(&mp->list);
+ free(mp);
+ found = 1;
+ break;
+ }
+ }
+ ASSERT(found);
+ ASSERT(!list_empty(&mg->mountpoints));
+}
+
+void got_mount_result(struct mountgroup *mg, int result, int ci, int another)
{
struct mg_member *memb;
memb = find_memb_nodeid(mg, our_nodeid);
- log_group(mg, "mount_result: kernel_mount_error %d first_mounter %d "
- "opts %x", result, mg->first_mounter, memb->opts);
+ log_group(mg, "got_mount_result: ci %d result %d another %d "
+ "first_mounter %d opts %x",
+ ci, result, another, mg->first_mounter, memb->opts);
+
+ mg->mount_client = 0;
+ mg->mount_client_fd = 0;
+
+ if (another) {
+ if (result)
+ remove_failed_mountpoint(mg, ci);
+ return;
+ }
mg->kernel_mount_done = 1;
mg->kernel_mount_error = result;
More information about the Cluster-devel
mailing list