Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842022
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/gfs2/mount/util.c b/gfs2/mount/util.c
index fecacea56..48b0b39e7 100644
--- a/gfs2/mount/util.c
+++ b/gfs2/mount/util.c
@@ -1,554 +1,558 @@
#include "util.h"
#include "libgfscontrol.h"
extern char *prog_name;
extern char *fsname;
extern int verbose;
static int gfs_controld_fd;
/* opt_map stuff from util-linux */
struct opt_map {
char *opt; /* option name */
int skip; /* skip in mtab option string (gfs: not used) */
int inv; /* true if flag value should be inverted */
int mask; /* flag mask value */
};
static struct opt_map opt_map[] = {
{ "defaults", 0, 0, 0 }, /* default options */
{ "ro", 1, 0, MS_RDONLY }, /* read-only */
{ "rw", 1, 1, MS_RDONLY }, /* read-write */
{ "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
{ "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
{ "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
{ "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
{ "dev", 0, 1, MS_NODEV }, /* interpret device files */
{ "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
{ "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
{ "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
{ "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
{ "bind", 0, 0, MS_BIND }, /* Remount part of tree elsewhere */
{ "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
{ "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
{ "atime", 0, 1, MS_NOATIME }, /* Update access time */
{ "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
{ "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
{ "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
/* options used by the mount command only (not in sys/mount.h): */
{ "dirsync", 0, 0, 0 }, /* synchronous directory modifications */
{ "loop", 1, 0, 0 }, /* use a loop device */
{ "auto", 0, 1, 0 }, /* Can be mounted using -a */
{ "noauto", 0, 0, 0 }, /* Can only be mounted explicitly */
{ "users", 0, 0, 0 }, /* Allow ordinary user to mount */
{ "nousers", 0, 1, 0 }, /* Forbid ordinary user to mount */
{ "user", 0, 0, 0 }, /* Allow ordinary user to mount */
{ "nouser", 0, 1, 0 }, /* Forbid ordinary user to mount */
{ "owner", 0, 0, 0 }, /* Let the owner of the device mount */
{ "noowner", 0, 1, 0 }, /* Device owner has no special privs */
{ "_netdev", 0, 0, 0 }, /* Network device required (netfs) */
{ NULL, 0, 0, 0 }
};
/* if option has a corresponding MS_XXX, set the bit in the flags */
static int set_flag(char *o, int *flags)
{
struct opt_map *om;
for (om = opt_map; om->opt; om++) {
if (strcmp(om->opt, o))
continue;
if (om->inv)
*flags &= ~om->mask;
else
*flags |= om->mask;
log_debug(" %s flag %x for \"%s\", flags = %x",
om->inv ? "clear" : "set", om->mask, om->opt, *flags);
return 1;
}
return 0;
}
/* opts is the string of all mount options, this function finds
the options that have MS_XXX flags and sets the appropriate flag
bit. The options without an MS_ flag are copied into the extra
string. The values of some specific options are saved for later
internal use. */
void parse_opts(struct mount_options *mo)
{
char data[PATH_MAX+1];
char *options, *o, *v;
int extra_len = 0;
log_debug("parse_opts: opts = \"%s\"", mo->opts);
memset(data, 0, sizeof(data));
strncpy(data, mo->opts, PATH_MAX);
for (options = data; (o = strsep(&options, ",")); ) {
if (!*o)
continue;
if (set_flag(o, &mo->flags))
continue;
if (!strncmp("hostdata", o, 8)) {
if (mo->hostdata[0])
warn("duplicate hostdata strings");
else
strcat(mo->hostdata, o);
continue;
}
if (extra_len + 1 + strlen(o) > PATH_MAX)
die("extra options string is too long\n");
if (mo->extra[0]) {
strcat(mo->extra, ",");
extra_len += 1;
}
log_debug(" add extra %s", o);
strcat(mo->extra, o);
extra_len += strlen(o);
v = strchr(o, '=');
if (v)
*v++ = 0;
/* we grab these now so we don't have to parse them out
again later when doing proto-specific stuff */
if (!strcmp(o, "lockproto")) {
if (!v)
die("option lockproto needs value\n");
strncpy(mo->lockproto, v, 255);
}
if (!strcmp(o, "locktable")) {
if (!v)
die("option locktable needs value\n");
strncpy(mo->locktable, v, 255);
}
}
log_debug("parse_opts: flags = %x", mo->flags);
log_debug("parse_opts: extra = \"%s\"", mo->extra);
log_debug("parse_opts: hostdata = \"%s\"", mo->hostdata);
log_debug("parse_opts: lockproto = \"%s\"", mo->lockproto);
log_debug("parse_opts: locktable = \"%s\"", mo->locktable);
}
/* - when unmounting, we don't know the dev and need this function to set it;
we also want to select the _last_ line with a matching dir since it will
be the top-most fs that the umount(2) will unmount
- when mounting, we do know the dev and need this function to use it in the
comparison (for multiple fs's with the same mountpoint) */
void read_proc_mounts(struct mount_options *mo)
{
FILE *file;
char line[PATH_MAX];
char path[PATH_MAX];
char type[PATH_MAX];
char opts[PATH_MAX];
char device[PATH_MAX];
char save_line[PATH_MAX];
char save_opts[PATH_MAX];
char save_device[PATH_MAX];
int found = 0;
file = fopen("/proc/mounts", "r");
if (!file)
die("can't open /proc/mounts: %s\n", strerror(errno));
while (fgets(line, PATH_MAX, file)) {
if (sscanf(line, "%s %s %s %s", device, path, type, opts) != 4)
continue;
if (strcmp(path, mo->dir))
continue;
if (mo->dev[0] && strcmp(device, mo->dev))
continue;
if (strcmp(type, fsname))
die("%s is not a %s filesystem\n", mo->dir, fsname);
/* when there is an input dev specified (mount), we should get
only one matching line; when there is no input dev specified
(umount), we want the _last_ matching line */
strncpy(save_device, device, PATH_MAX);
strncpy(save_opts, opts, PATH_MAX);
strncpy(save_line, line, PATH_MAX);
found = 1;
}
fclose(file);
if (!found)
die("can't find /proc/mounts entry for directory %s\n", mo->dir);
else {
strncpy(mo->dev, save_device, PATH_MAX);
strncpy(mo->opts, save_opts, PATH_MAX);
strncpy(mo->proc_entry, save_line, PATH_MAX);
}
log_debug("read_proc_mounts: device = \"%s\"", mo->dev);
log_debug("read_proc_mounts: opts = \"%s\"", mo->opts);
}
void gfs2_inum_in(struct gfs2_inum *no, char *buf)
{
struct gfs2_inum *str = (struct gfs2_inum *)buf;
no->no_formal_ino = be64_to_cpu(str->no_formal_ino);
no->no_addr = be64_to_cpu(str->no_addr);
}
void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf)
{
struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf;
mh->mh_magic = be32_to_cpu(str->mh_magic);
mh->mh_type = be32_to_cpu(str->mh_type);
mh->mh_format = be32_to_cpu(str->mh_format);
}
void gfs2_sb_in(struct gfs2_sb *sb, char *buf)
{
struct gfs2_sb *str = (struct gfs2_sb *)buf;
gfs2_meta_header_in(&sb->sb_header, buf);
sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
sb->sb_bsize = be32_to_cpu(str->sb_bsize);
sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
}
int get_sb(char *device, struct gen_sb *sb_out)
{
int fd;
fd = open(device, O_RDONLY);
if (fd < 0)
die("can't open %s: %s\n", device, strerror(errno));
if (!strcmp(fsname, "gfs2")) {
char buf[GFS2_BASIC_BLOCK];
struct gfs2_sb sb;
do_lseek(fd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK);
do_read(fd, buf, GFS2_BASIC_BLOCK);
gfs2_sb_in(&sb, buf);
if (sb.sb_header.mh_magic != GFS2_MAGIC ||
sb.sb_header.mh_type != GFS2_METATYPE_SB) {
die("there isn't a GFS2 filesystem on %s, "
"magic=%x type=%x\n", device,
sb.sb_header.mh_magic, sb.sb_header.mh_type);
}
if (sb.sb_fs_format != GFS2_FORMAT_FS ||
sb.sb_multihost_format != GFS2_FORMAT_MULTI) {
die("there appears to be a GFS, not GFS2, filesystem "
"on %s\n", device);
}
strncpy(sb_out->lockproto, sb.sb_lockproto, 256);
strncpy(sb_out->locktable, sb.sb_locktable, 256);
} else if (!strcmp(fsname, "gfs")) {
char buf[GFS_BASIC_BLOCK];
struct gfs_sb sb;
do_lseek(fd, GFS_SB_ADDR * GFS_BASIC_BLOCK);
do_read(fd, buf, GFS2_BASIC_BLOCK);
gfs_sb_in(&sb, buf);
if (sb.sb_header.mh_magic != GFS_MAGIC ||
sb.sb_header.mh_type != GFS_METATYPE_SB) {
die("there isn't a GFS filesystem on %s\n", device);
}
if (sb.sb_fs_format != GFS_FORMAT_FS ||
sb.sb_multihost_format != GFS_FORMAT_MULTI) {
die("there appears to be a GFS2, not GFS, filesystem "
"on %s\n", device);
}
strncpy(sb_out->lockproto, sb.sb_lockproto, 256);
strncpy(sb_out->locktable, sb.sb_locktable, 256);
}
close(fd);
return 0;
}
char *select_lockproto(struct mount_options *mo, struct gen_sb *sb)
{
/* find the effective lockproto, proto specified in mount options
overrides the sb lockproto */
if (mo->lockproto[0])
return mo->lockproto;
else
return sb->lockproto;
}
int lock_dlm_join(struct mount_options *mo, struct gen_sb *sb)
{
struct gfsc_mount_args ma;
int fd, rv, result;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.proto, "lock_dlm", PATH_MAX);
strncpy(ma.options, mo->opts, PATH_MAX);
strncpy(ma.dev, mo->dev, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
fd = gfsc_fs_connect();
if (fd < 0) {
warn("gfs_controld join connect error: %s", strerror(errno));
return fd;
}
/* tell gfs_controld to join the mountgroup */
rv = gfsc_fs_join(fd, &ma);
if (rv < 0) {
warn("gfs_controld join write error: %s", strerror(errno));
goto fail;
}
/* read the result of the join from gfs_controld */
rv = gfsc_fs_result(fd, &result, &ma);
if (rv < 0) {
warn("gfs_controld result read error: %s", strerror(errno));
goto fail;
}
rv = result;
switch (rv) {
case 0:
case -EALREADY:
break;
case -EPROTONOSUPPORT:
warn("lockproto not supported");
goto fail;
case -EOPNOTSUPP:
warn("jid, first and id are reserved options");
goto fail;
case -EBADFD:
warn("no colon found in table name");
goto fail;
case -ENAMETOOLONG:
warn("fs name too long");
goto fail;
case -ESTALE:
warn("fs is being unmounted");
goto fail;
case -EADDRINUSE:
warn("different fs appears to exist with the same name");
goto fail;
case -EBUSY:
warn("mount point already used or other mount in progress");
goto fail;
case -ENOMEM:
warn("out of memory");
goto fail;
case -EBADR:
warn("fs is for a different cluster");
goto fail;
case -ENOANO:
warn("node not a member of the default fence domain");
goto fail;
case -EROFS:
warn("read-only mount invalid with spectator option");
goto fail;
case -EMLINK:
warn("option string too long");
goto fail;
default:
warn("gfs_controld join error: %d", rv);
goto fail;
}
/*
* In addition to the result, gfs_controld also returns
* "hostdata=jid=X:id=Y:first=Z" in ma.hostdata.
* This is first combined with any hostdata the user gave on
* the command line and then the full hostdata is combined
* with the "extra" mount otions into the "extra_plus" string.
*/
if (strlen(mo->hostdata) + strlen(ma.hostdata) + 1 > PATH_MAX) {
warn("hostdata too long");
rv = -1;
goto fail;
}
if (!mo->hostdata[0])
snprintf(mo->hostdata, PATH_MAX, "%s", ma.hostdata);
else {
char *p = strstr(ma.hostdata, "=") + 1;
strcat(mo->hostdata, ":");
strcat(mo->hostdata, p);
}
log_debug("lock_dlm_join: hostdata: \"%s\"", mo->hostdata);
if (strlen(mo->extra) == 0)
snprintf(mo->extra_plus, PATH_MAX, "%s", mo->hostdata);
else
snprintf(mo->extra_plus, PATH_MAX, "%s,%s",
mo->extra, mo->hostdata);
/* keep gfs_controld connection open and reuse it below to
send the result of mount(2) to gfs_controld, except in
the case of another mount (EALREADY) */
if (rv == -EALREADY)
gfsc_fs_disconnect(fd);
else
gfs_controld_fd = fd;
return 0;
fail:
gfsc_fs_disconnect(fd);
return rv;
}
void lock_dlm_mount_done(struct mount_options *mo, struct gen_sb *sb,
int result)
{
struct gfsc_mount_args ma;
int rv;
if (!gfs_controld_fd)
return;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.proto, "lock_dlm", PATH_MAX);
strncpy(ma.options, mo->opts, PATH_MAX);
strncpy(ma.dev, mo->dev, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
/* tell gfs_controld the result of mount(2) */
rv = gfsc_fs_mount_done(gfs_controld_fd, &ma, result);
if (rv)
warn("gfs_controld mount_done write error: %s", strerror(errno));
gfsc_fs_disconnect(gfs_controld_fd);
}
int lock_dlm_leave(struct mount_options *mo, struct gen_sb *sb, int mnterr)
{
struct gfsc_mount_args ma;
int rv;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
+ if (mo->locktable[0])
+ strncpy(ma.table, mo->locktable, PATH_MAX);
+ else
+ strncpy(ma.table, sb->locktable, PATH_MAX);
rv = gfsc_fs_leave(&ma, mnterr);
if (rv)
warn("leave: gfs_controld leave error: %s", strerror(errno));
return rv;
}
int lock_dlm_remount(struct mount_options *mo, struct gen_sb *sb)
{
struct gfsc_mount_args ma;
char *mode;
int fd, rv, result;
memset(&ma, 0, sizeof(ma));
/* FIXME: how to check for spectator remounts, we want
to disallow remount to/from spectator */
if (mo->flags & MS_RDONLY)
mode = "ro";
else
mode = "rw";
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.options, mode, PATH_MAX);
fd = gfsc_fs_connect();
if (fd < 0) {
warn("gfs_controld remount connect error: %s", strerror(errno));
return fd;
}
/* tell gfs_controld about the new mount options */
rv = gfsc_fs_remount(fd, &ma);
if (rv) {
warn("gfs_controld remount write error: %s", strerror(errno));
goto out;
}
/* read the result of the remount from gfs_controld */
rv = gfsc_fs_result(fd, &result, &ma);
if (rv < 0) {
warn("gfs_controld result read error: %s", strerror(errno));
goto out;
}
rv = result;
if (rv)
warn("remount not allowed from gfs_controld");
out:
gfsc_fs_disconnect(fd);
return rv;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 11:07 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018644
Default Alt Text
(15 KB)
Attached To
Mode
rR Resource Agents
Attached
Detach File
Event Timeline
Log In to Comment