[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