From mboxrd@z Thu Jan 1 00:00:00 1970 From: teigland@sourceware.org Date: 20 Dec 2006 19:14:41 -0000 Subject: [Cluster-devel] cluster/group/gfs_controld lock_dlm.h main.c r ... Message-ID: <20061220191441.4410.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Branch: RHEL5 Changes by: teigland at sourceware.org 2006-12-20 19:14:41 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&only_with_tag=RHEL5&r1=1.21.2.5&r2=1.21.2.6 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/group/gfs_controld/main.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.18.2.9&r2=1.18.2.10 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/group/gfs_controld/recover.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.23.2.4&r2=1.23.2.5 --- cluster/group/gfs_controld/lock_dlm.h 2006/12/19 17:07:12 1.21.2.5 +++ cluster/group/gfs_controld/lock_dlm.h 2006/12/20 19:14:41 1.21.2.6 @@ -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:24:29 1.18.2.9 +++ cluster/group/gfs_controld/main.c 2006/12/20 19:14:41 1.18.2.10 @@ -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:59 1.23.2.4 +++ cluster/group/gfs_controld/recover.c 2006/12/20 19:14:41 1.23.2.5 @@ -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 : */ @@ -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;