commit 9fb243836b132d7699af9405307279174d23ba33 Author: Bob Peterson <rpeterso@redhat.com> Date: Thu Aug 8 14:50:04 2013 -0500 gfs2_tool: Update /etc/mtab with metafs mounts, handle interrupts This patch gives libgfs2 the ability to add the metafs to the /etc/mtab file, so that a "mount" will show it and "umount -a -tgfs2" will unmount it. At the same time, it also catches interrupt signals while gfs2_tool df is running, and if interrupted, it unmounts the metafs. rhbz#994643 diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h index 95a4ddb..90bfe08 100644 --- a/gfs2/libgfs2/libgfs2.h +++ b/gfs2/libgfs2/libgfs2.h @@ -541,6 +541,8 @@ extern int gfs2_query(int *setonabort, struct gfs2_options *opts, /* misc.c */ #define SYS_BASE "/sys/fs/gfs2" +extern int metafs_interrupted; + extern char *get_list(void); extern char **str2lines(char *str); extern char *find_debugfs_mount(void); diff --git a/gfs2/libgfs2/misc.c b/gfs2/libgfs2/misc.c index 3ff1dc4..590800f 100644 --- a/gfs2/libgfs2/misc.c +++ b/gfs2/libgfs2/misc.c @@ -30,12 +30,14 @@ #include <sys/statfs.h> #include <mntent.h> #include <sys/time.h> +#include <signal.h> #include "libgfs2.h" #define PAGE_SIZE (4096) static char sysfs_buf[PAGE_SIZE]; +int metafs_interrupted = 0; int compute_heightsize(struct gfs2_sbd *sdp, uint64_t *heightsize, uint32_t bsize1, int diptrs, int inptrs) @@ -221,30 +223,47 @@ lock_for_admin(struct gfs2_sbd *sdp) printf("Got it.\n"); } -void -mount_gfs2_meta(struct gfs2_sbd *sdp) +static void remove_mtab_entry(struct gfs2_sbd *sdp) { - int ret; - - memset(sdp->metafs_path, 0, PATH_MAX); - snprintf(sdp->metafs_path, PATH_MAX - 1, "/tmp/.gfs2meta.XXXXXX"); - - if(!mkdtemp(sdp->metafs_path)) - die("Couldn't create %s : %s\n", sdp->metafs_path, + FILE *mtab, *mtabnew; + struct mntent *mountent; + char mtab_tmpfn[PATH_MAX]; + int error, fd; + + mtab = setmntent("/etc/mtab", "rt"); + if (mtab == NULL) + die("Couldn't open /etc/mtab for writing: %s\n", + strerror(errno)); + strcpy(mtab_tmpfn, "/etc/mtab.XXXXXX"); + fd = mkstemp(mtab_tmpfn); + if (fd < 0) + die("Couldn't open temporary mtab file for writing: %s\n", strerror(errno)); - ret = mount(sdp->path_name, sdp->metafs_path, "gfs2meta", 0, NULL); - if (ret) { - rmdir(sdp->metafs_path); - die("Couldn't mount %s : %s\n", sdp->metafs_path, + mtabnew = fdopen(fd, "wt"); + if (mtabnew == NULL) + die("Couldn't open %s for writing : %s\n", mtab_tmpfn, strerror(errno)); + + while ((mountent = getmntent(mtab)) != NULL) { + if (!strcmp(mountent->mnt_dir, sdp->metafs_path)) + continue; + error = addmntent(mtabnew, mountent); + if (error) + die("Unable to remove mount entry from mtab.\n"); } - lock_for_admin(sdp); + + endmntent(mtab); + fclose(mtabnew); + close(fd); + if (rename(mtab_tmpfn, "/etc/mtab")) + fprintf(stderr, "Unable to remove mount entry from mtab.\n"); } void cleanup_metafs(struct gfs2_sbd *sdp) { int ret; + struct sigaction sa = { .sa_handler = SIG_DFL }; if (sdp->metafs_fd <= 0) return; @@ -257,6 +276,68 @@ void cleanup_metafs(struct gfs2_sbd *sdp) sdp->metafs_path, strerror(errno)); else rmdir(sdp->metafs_path); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGCONT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + metafs_interrupted = 0; + remove_mtab_entry(sdp); +} + +static void sighandler(int error) +{ + metafs_interrupted = 1; +} + +void +mount_gfs2_meta(struct gfs2_sbd *sdp) +{ + int ret; + struct mntent ment; + char mnt_type[5] = "gfs2"; + char mnt_opts[9] = "gfs2meta"; + FILE *mtab; + struct sigaction sa = { .sa_handler = &sighandler }; + + memset(sdp->metafs_path, 0, PATH_MAX); + snprintf(sdp->metafs_path, PATH_MAX - 1, "/tmp/.gfs2meta.XXXXXX"); + + if(!mkdtemp(sdp->metafs_path)) + die("Couldn't create %s : %s\n", sdp->metafs_path, + strerror(errno)); + + mtab = setmntent("/etc/mtab", "at"); + if (mtab == NULL) + die("Couldn't open /etc/mtab for writing : %s\n", + strerror(errno)); + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGCONT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + ret = mount(sdp->path_name, sdp->metafs_path, "gfs2meta", 0, NULL); + if (ret) { + rmdir(sdp->metafs_path); + die("Couldn't mount %s : %s\n", sdp->metafs_path, + strerror(errno)); + } + ment.mnt_fsname = sdp->path_name; + ment.mnt_dir = sdp->metafs_path; + ment.mnt_type = mnt_type; + ment.mnt_opts = mnt_opts; + addmntent(mtab, &ment); + endmntent(mtab); + lock_for_admin(sdp); } static char *__get_sysfs(const char *fsname, const char *filename) diff --git a/gfs2/mkfs/main_grow.c b/gfs2/mkfs/main_grow.c index 9aba5da..4b87a91 100644 --- a/gfs2/mkfs/main_grow.c +++ b/gfs2/mkfs/main_grow.c @@ -343,6 +343,8 @@ main_grow(int argc, char *argv[]) /* we're only going to write out new RG information after */ /* the existing RGs, and only write to the index at EOF. */ ri_update(sdp, rindex_fd, &rgcount, &sane); + if (metafs_interrupted) + goto out; fssize = filesystem_size(sdp); if (!sdp->rgtree.osi_node) { log_err(_("Error: No resource groups found.\n")); @@ -363,9 +365,15 @@ main_grow(int argc, char *argv[]) else { int old_rg_count; + if (metafs_interrupted) + goto out; compute_rgrp_layout(sdp, &sdp->rgtree, TRUE); + if (metafs_interrupted) + goto out; print_info(sdp); initialize_new_portion(sdp, &old_rg_count); + if (metafs_interrupted) + goto out; fix_rindex(sdp, rindex_fd, old_rg_count); } out: @@ -377,5 +385,6 @@ main_grow(int argc, char *argv[]) } close(sdp->path_fd); sync(); - log_notice( _("gfs2_grow complete.\n")); + if (!metafs_interrupted) + log_notice( _("gfs2_grow complete.\n")); } diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c index c0945d1..8e6a3a9 100644 --- a/gfs2/mkfs/main_jadd.c +++ b/gfs2/mkfs/main_jadd.c @@ -509,6 +509,10 @@ main_jadd(int argc, char *argv[]) for (sdp->md.journals = sdp->orig_journals; sdp->md.journals < total; sdp->md.journals++) { + if (metafs_interrupted) { + cleanup_metafs(&sbd); + exit(130); + } add_ir(sdp); add_sc(sdp); add_qc(sdp); diff --git a/gfs2/quota/check.c b/gfs2/quota/check.c index 2635725..4437fd9 100644 --- a/gfs2/quota/check.c +++ b/gfs2/quota/check.c @@ -249,6 +249,8 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline, uint64_t end = fe->fe_logical + fe->fe_length, val_off; unsigned int v_off; + if (metafs_interrupted) + break; end = end > quota_file_size ? quota_file_size : end; /* we only need to get the value fields, not the whole quota * This also works when struct gfs2_quota straddle page @@ -514,6 +516,8 @@ set_list(struct gfs2_sbd *sdp, commandline_t *comline, int user, } for (tmp = list->next; tmp != list; tmp = tmp->next) { + if (metafs_interrupted) + goto out; v = osi_list_entry(tmp, values_t, v_list); offset = (2 * (uint64_t)v->v_id + ((user) ? 0 : 1)) * diff --git a/gfs2/quota/main.c b/gfs2/quota/main.c index 07aed6c..b33fdc2 100644 --- a/gfs2/quota/main.c +++ b/gfs2/quota/main.c @@ -394,18 +394,20 @@ do_reset(struct gfs2_sbd *sdp, commandline_t *comline) strerror(errno)); } - read_quota_internal(fd, 0, GQ_ID_USER, &q); - write_quota_internal(fd, 0, GQ_ID_USER, &q); - - read_quota_internal(fd, 0, GQ_ID_GROUP, &q); - write_quota_internal(fd, 0, GQ_ID_GROUP, &q); - - /* truncate the quota file such that only the first - * two quotas(uid=0 and gid=0) remain. - */ - if (ftruncate(fd, (sizeof(struct gfs2_quota)) * 2)) - die("couldn't truncate quota file %s\n", strerror(errno)); - + if (!metafs_interrupted) { + read_quota_internal(fd, 0, GQ_ID_USER, &q); + write_quota_internal(fd, 0, GQ_ID_USER, &q); + + read_quota_internal(fd, 0, GQ_ID_GROUP, &q); + write_quota_internal(fd, 0, GQ_ID_GROUP, &q); + + /* truncate the quota file such that only the first + * two quotas(uid=0 and gid=0) remain. + */ + if (ftruncate(fd, (sizeof(struct gfs2_quota)) * 2)) + die("couldn't truncate quota file %s\n", + strerror(errno)); + } close(fd); close(sdp->metafs_fd); cleanup_metafs(sdp); @@ -490,6 +492,8 @@ do_list(struct gfs2_sbd *sdp, commandline_t *comline) struct fiemap_extent *fe = &fmap2->fm_extents[i]; uint64_t end = fe->fe_logical + fe->fe_length; + if (metafs_interrupted) + goto fmap2_free; end = end > quota_file_size ? quota_file_size : end; startid = DIV_RU(fe->fe_logical, sizeof(struct gfs2_quota)); if (startid % 2 != pass) @@ -553,7 +557,7 @@ do_get_one(struct gfs2_sbd *sdp, commandline_t *comline, char *filesystem) strcat(quota_file, "/quota"); fd = open(quota_file, O_RDONLY); - if (fd < 0) { + if (fd < 0 || metafs_interrupted) { close(sdp->metafs_fd); cleanup_metafs(sdp); die("can't open file %s: %s\n", quota_file, @@ -707,7 +711,7 @@ do_set(struct gfs2_sbd *sdp, commandline_t *comline) strcat(quota_file, "/quota"); fd = open(quota_file, O_RDWR); - if (fd < 0) { + if (fd < 0 || metafs_interrupted) { close(sdp->metafs_fd); cleanup_metafs(sdp); die("can't open file %s: %s\n", quota_file, diff --git a/gfs2/tool/df.c b/gfs2/tool/df.c index c4a6d93..1adbc10 100644 --- a/gfs2/tool/df.c +++ b/gfs2/tool/df.c @@ -163,8 +163,16 @@ do_df_one(char *path) /* Read the master statfs file */ mount_gfs2_meta(&sbd); + if (metafs_interrupted) { + cleanup_metafs(&sbd); + exit(130); + } sprintf(statfs_fn, "%s/statfs", sbd.metafs_path); statfs_fd = open(statfs_fn, O_RDONLY); + if (metafs_interrupted) { + cleanup_metafs(&sbd); + exit(130); + } do_read(statfs_fd, buf, sizeof(struct gfs2_statfs_change)); gfs2_statfs_change_in(&sc, (char *)&buf); diff --git a/gfs2/tool/misc.c b/gfs2/tool/misc.c index 4176882..739f3a8 100644 --- a/gfs2/tool/misc.c +++ b/gfs2/tool/misc.c @@ -448,11 +448,19 @@ print_journals(int argc, char **argv) sprintf(jindex_name, "%s/jindex", sbd.metafs_path); jindex = opendir(jindex_name); + if (metafs_interrupted) { + cleanup_metafs(&sbd); + exit(130); + } if (!jindex) { die( _("Can't open %s\n"), jindex_name); } else { jcount = 0; while ((journal = readdir(jindex))) { + if (metafs_interrupted) { + cleanup_metafs(&sbd); + exit(130); + } if (journal->d_name[0] == '.') continue; sprintf(jname, "%s/%s", jindex_name, journal->d_name);