diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c index c542480..ea89c96 100644 --- a/gfs2/mkfs/main_jadd.c +++ b/gfs2/mkfs/main_jadd.c @@ -42,15 +42,13 @@ struct jadd_opts { #define JA_FL_SET 0 #define JA_FL_CLEAR 1 -static void set_flags(int fd, int op, uint32_t flags) +static int set_flags(int fd, int op, uint32_t flags) { - int err; uint32_t val; - err = ioctl(fd, FS_IOC_GETFLAGS, &val); - if (err) { + if (ioctl(fd, FS_IOC_GETFLAGS, &val)) { perror("GETFLAGS"); - exit(EXIT_FAILURE); + return -1; } if (op == JA_FL_SET) @@ -58,11 +56,11 @@ static void set_flags(int fd, int op, uint32_t flags) else if (op == JA_FL_CLEAR) val &= ~flags; - err = ioctl(fd, FS_IOC_SETFLAGS, &val); - if (err) { + if (ioctl(fd, FS_IOC_SETFLAGS, &val)) { perror("SETFLAGS"); - exit(EXIT_FAILURE); + return -1; } + return 0; } static int rename2system(struct jadd_opts *opts, const char *new_dir, const char *new_name) @@ -243,188 +241,214 @@ static void print_results(struct jadd_opts *opts) static int create_new_inode(struct jadd_opts *opts, uint64_t *addr) { char *name = opts->new_inode; - int fd; - int error; + int fd, error = 0; for (;;) { fd = open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600); if (fd >= 0) break; if (errno == EEXIST) { - error = unlink(name); - if (error){ + if (unlink(name)) { perror("unlink"); - exit(EXIT_FAILURE); + return -1; } - } else{ - perror("create"); - exit(EXIT_FAILURE); + continue; } + perror("create"); + return -1; } + if (addr != NULL) { struct stat st; - fstat(fd, &st); + if ((error = fstat(fd, &st))) { + perror("fstat"); + return close(fd); + } *addr = st.st_ino; } return fd; } -static void add_ir(struct jadd_opts *opts) +static int add_ir(struct jadd_opts *opts) { - int fd; + int fd, error = 0; char new_name[256]; - int error; + struct gfs2_inum_range ir; - fd = create_new_inode(opts, NULL); + if ((fd = create_new_inode(opts, NULL)) < 0) + return fd; - { - struct gfs2_inum_range ir; + if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL))) + goto close_fd; - set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); - memset(&ir, 0, sizeof(struct gfs2_inum_range)); - if (write(fd, (void*)&ir, sizeof(struct gfs2_inum_range)) != - sizeof(struct gfs2_inum_range)) { - perror("add_ir"); - exit(EXIT_FAILURE); - } + memset(&ir, 0, sizeof(struct gfs2_inum_range)); + if (write(fd, (void*)&ir, sizeof(struct gfs2_inum_range)) != + sizeof(struct gfs2_inum_range)) { + perror("add_ir write"); + error = -1; + goto close_fd; + } + + if ((error = fsync(fd))) { + perror("add_ir fsync"); + goto close_fd; } - close(fd); sprintf(new_name, "inum_range%u", opts->journals); error = rename2system(opts, opts->per_node, new_name); - if (error < 0 && errno != EEXIST){ + if (error < 0 && errno != EEXIST) { perror("add_ir rename2system"); - exit(EXIT_FAILURE); + goto close_fd; } +close_fd: + return close(fd) || error; } -static void add_sc(struct jadd_opts *opts) +static int add_sc(struct jadd_opts *opts) { - int fd; + int fd, error = 0; char new_name[256]; - int error; + struct gfs2_statfs_change sc; - fd = create_new_inode(opts, NULL); + if ((fd = create_new_inode(opts, NULL)) < 0) + return fd; - { - struct gfs2_statfs_change sc; - set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); + if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL))) + goto close_fd; - memset(&sc, 0, sizeof(struct gfs2_statfs_change)); - if (write(fd, (void*)&sc, sizeof(struct gfs2_statfs_change)) != - sizeof(struct gfs2_statfs_change)) { - perror("add_sc"); - exit(EXIT_FAILURE); - } + memset(&sc, 0, sizeof(struct gfs2_statfs_change)); + if (write(fd, (void*)&sc, sizeof(struct gfs2_statfs_change)) != + sizeof(struct gfs2_statfs_change)) { + perror("add_sc write"); + error = -1; + goto close_fd; } - close(fd); + if ((error = fsync(fd))) { + perror("add_sc fsync"); + goto close_fd; + } sprintf(new_name, "statfs_change%u", opts->journals); error = rename2system(opts, opts->per_node, new_name); if (error < 0 && errno != EEXIST){ perror("add_sc rename2system"); - exit(EXIT_FAILURE); + goto close_fd; } +close_fd: + return close(fd) || error; } -static void add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) +static int add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) { - int fd; - char new_name[256]; - int error; - - fd = create_new_inode(opts, NULL); - - { - char buf[sdp->bsize]; - unsigned int blocks = - sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift); - unsigned int x; - struct gfs2_meta_header mh; - - set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); - memset(buf, 0, sdp->bsize); - - for (x=0; xbsize) != sdp->bsize) { - perror("add_qc"); - exit(EXIT_FAILURE); - } + int fd, error = 0; + char new_name[256], buf[sdp->bsize]; + unsigned int blocks = + sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift); + unsigned int x; + struct gfs2_meta_header mh; + + if ((fd = create_new_inode(opts, NULL)) < 0) + return fd; + + if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL))) + goto close_fd; + + memset(buf, 0, sdp->bsize); + for (x=0; xbsize) != sdp->bsize) { + perror("add_qc write"); + error = -1; + goto close_fd; } + } - lseek(fd, 0, SEEK_SET); - - memset(&mh, 0, sizeof(struct gfs2_meta_header)); - mh.mh_magic = GFS2_MAGIC; - mh.mh_type = GFS2_METATYPE_QC; - mh.mh_format = GFS2_FORMAT_QC; - gfs2_meta_header_out(&mh, buf); + if ((error = lseek(fd, 0, SEEK_SET)) < 0) { + perror("add_qc lseek"); + goto close_fd; + } - for (x=0; xbsize) != sdp->bsize) { - perror("add_qc"); - exit(EXIT_FAILURE); - } + memset(&mh, 0, sizeof(struct gfs2_meta_header)); + mh.mh_magic = GFS2_MAGIC; + mh.mh_type = GFS2_METATYPE_QC; + mh.mh_format = GFS2_FORMAT_QC; + gfs2_meta_header_out(&mh, buf); + + for (x=0; xbsize) != sdp->bsize) { + perror("add_qc write"); + error = 1; + goto close_fd; } - - error = fsync(fd); - if (error){ + if ((error = fsync(fd))) { perror("add_qc fsync"); - exit(EXIT_FAILURE); + goto close_fd; } } - close(fd); - sprintf(new_name, "quota_change%u", opts->journals); error = rename2system(opts, opts->per_node, new_name); if (error < 0 && errno != EEXIST){ perror("add_qc rename2system"); - exit(EXIT_FAILURE); + goto close_fd; } +close_fd: + return close(fd) || error; } -static void gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) +static int gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) { struct statfs statbuf; + if (statfs(opts->path, &statbuf) < 0) { perror(opts->path); - exit(EXIT_FAILURE); + return -1; } + sdp->bsize = statbuf.f_bsize; sdp->blks_total = statbuf.f_blocks; sdp->blks_alloced = sdp->blks_total - statbuf.f_bfree; + + return 0; } -static void find_current_journals(struct jadd_opts *opts) +static int find_current_journals(struct jadd_opts *opts) { struct dirent *dp; DIR *dirp; unsigned existing_journals = 0; + int ret = 0; dirp = opendir(opts->jindex); if (!dirp) { perror("jindex"); - exit(EXIT_FAILURE); + ret = -1; + goto out; } while (dirp) { if ((dp = readdir(dirp)) != NULL) { if (strncmp(dp->d_name, "journal", 7) == 0) existing_journals++; } else - goto close; + goto close_fd; } -close: - closedir(dirp); +close_fd: + if ((ret = closedir(dirp))) + goto out; + if (existing_journals == 0) { - die( _("No journals found. Did you run mkfs.gfs2 correctly?\n")); + errno = EINVAL; + perror("No journals found. Did you run mkfs.gfs2 correctly?\n"); + ret = -1; + goto out; } opts->orig_journals = existing_journals; +out: + return ret; } #ifdef GFS2_HAS_LH_V2 @@ -450,83 +474,88 @@ static uint64_t find_block_address(int fd, off_t offset, unsigned bsize) } #endif -static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) +static int add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) { - int fd; - char new_name[256]; - int error; - uint64_t addr; - - fd = create_new_inode(opts, &addr); - - { - char buf[sdp->bsize]; - unsigned int blocks = - sdp->jsize << (20 - sdp->sd_sb.sb_bsize_shift); - unsigned int x; - struct gfs2_log_header lh; - uint64_t seq = RANDOM(blocks); - off_t off = 0; - - set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); - memset(buf, 0, sdp->bsize); - for (x=0; xbsize) != sdp->bsize) { - perror("add_j"); - exit(EXIT_FAILURE); - } + int fd, error = 0; + char new_name[256], buf[sdp->bsize]; + unsigned int x, blocks = + sdp->jsize << (20 - sdp->sd_sb.sb_bsize_shift); + struct gfs2_log_header lh; + uint64_t seq = RANDOM(blocks), addr; + off_t off = 0; + + if ((fd = create_new_inode(opts, &addr)) < 0) + return fd; + + if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL))) + goto close_fd; + + memset(buf, 0, sdp->bsize); + for (x=0; xbsize) != sdp->bsize) { + perror("add_j write"); + error = -1; + goto close_fd; } + } - lseek(fd, 0, SEEK_SET); + if ((error = lseek(fd, 0, SEEK_SET)) < 0) { + perror("add_j lseek"); + goto close_fd; + } - memset(&lh, 0, sizeof(struct gfs2_log_header)); - lh.lh_header.mh_magic = GFS2_MAGIC; - lh.lh_header.mh_type = GFS2_METATYPE_LH; - lh.lh_header.mh_format = GFS2_FORMAT_LH; - lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT; + memset(&lh, 0, sizeof(struct gfs2_log_header)); + lh.lh_header.mh_magic = GFS2_MAGIC; + lh.lh_header.mh_type = GFS2_METATYPE_LH; + lh.lh_header.mh_format = GFS2_FORMAT_LH; + lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT; #ifdef GFS2_HAS_LH_V2 - lh.lh_flags |= GFS2_LOG_HEAD_USERSPACE; - lh.lh_jinode = addr; + lh.lh_flags |= GFS2_LOG_HEAD_USERSPACE; + lh.lh_jinode = addr; #endif - for (x=0; xlh_hash = cpu_to_be32(hash); + for (x=0; xlh_addr = cpu_to_be64( - find_block_address(fd, off, sdp->bsize)); - hash = lgfs2_log_header_crc(buf, sdp->bsize); - ((struct gfs2_log_header *)buf)->lh_crc = cpu_to_be32(hash); + uint64_t blk_addr = 0; #endif - if (write(fd, buf, sdp->bsize) != sdp->bsize) { - perror("add_j"); - exit(EXIT_FAILURE); - } - - if (++seq == blocks) - seq = 0; - off += sdp->bsize; + lh.lh_sequence = seq; + lh.lh_blkno = x; + gfs2_log_header_out(&lh, buf); + hash = lgfs2_log_header_hash(buf); + ((struct gfs2_log_header *)buf)->lh_hash = cpu_to_be32(hash); +#ifdef GFS2_HAS_LH_V2 + if (!(blk_addr = find_block_address(fd, off, sdp->bsize))) { + error = -1; + goto close_fd; + } + ((struct gfs2_log_header *)buf)->lh_addr = cpu_to_be64(blk_addr); + hash = lgfs2_log_header_crc(buf, sdp->bsize); + ((struct gfs2_log_header *)buf)->lh_crc = cpu_to_be32(hash); +#endif + if (write(fd, buf, sdp->bsize) != sdp->bsize) { + perror("add_j write"); + error = -1; + goto close_fd; } - error = fsync(fd); - if (error){ + if (++seq == blocks) + seq = 0; + off += sdp->bsize; + + if ((error = fsync(fd))) { perror("add_j fsync"); - exit(EXIT_FAILURE); + goto close_fd; } } - close(fd); - sprintf(new_name, "journal%u", opts->journals); error = rename2system(opts, opts->jindex, new_name); if (error < 0 && errno != EEXIST){ perror("add_j rename2system"); - exit(EXIT_FAILURE); + goto close_fd; } +close_fd: + return close(fd) || error; } static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) @@ -554,7 +583,7 @@ static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) printf( _("Available space : %*lu blks\n\n"), 10, sdp->blks_total - sdp->blks_alloced); errno = ENOSPC; - return 1; + return -1; } return 0; } @@ -581,35 +610,42 @@ int main(int argc, char *argv[]) sbd.path_fd = lgfs2_open_mnt_dir(opts.path, O_RDONLY|O_CLOEXEC, &mnt); if (sbd.path_fd < 0) { - fprintf(stderr, _("Error looking up mount '%s': %s\n"), opts.path, strerror(errno)); - exit(EXIT_FAILURE); + fprintf(stderr, "Error looking up mount '%s': %s\n", + opts.path, strerror(errno)); + ret = -1; + goto out; } if (mnt == NULL) { - fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), opts.path); - exit(EXIT_FAILURE); + fprintf(stderr, "%s: not a mounted gfs2 file system\n", opts.path); + ret = -1; + goto close_sb; } - gather_info(sdp, &opts); + + if ((ret = gather_info(sdp, &opts))) + goto close_sb; + mfs.context = copy_context_opt(mnt); - if (mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug)) { + if ((ret = mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug))) { perror("GFS2 metafs"); - exit(EXIT_FAILURE); + goto close_sb; } - if (build_paths(mfs.path, &opts)) { + if ((ret = build_paths(mfs.path, &opts))) { perror(_("Failed to build paths")); - exit(EXIT_FAILURE); + goto umount_meta; } - if (compute_constants(sdp)) { + if ((ret = compute_constants(sdp))) { perror(_("Failed to compute file system constants")); - exit(EXIT_FAILURE); + goto free_paths; } - find_current_journals(&opts); - ret = check_fit(sdp, &opts); - if (ret) { + if ((ret = find_current_journals(&opts))) + goto free_paths; + + if ((ret = check_fit(sdp, &opts))) { perror(_("Failed to add journals")); - goto out; + goto free_paths; } total = opts.orig_journals + opts.journals; @@ -617,23 +653,29 @@ int main(int argc, char *argv[]) opts.journals < total; opts.journals++) { if (metafs_interrupted) { - cleanup_metafs(&mfs); - exit(130); + errno = 130; + goto free_paths; } - add_ir(&opts); - add_sc(&opts); - add_qc(sdp, &opts); - add_j(sdp, &opts); + if ((ret = add_ir(&opts))) + goto free_paths; + if ((ret = add_sc(&opts))) + goto free_paths; + if ((ret = add_qc(sdp, &opts))) + goto free_paths; + if ((ret = add_j(sdp, &opts))) + goto free_paths; } -out: +free_paths: free(opts.new_inode); free(opts.per_node); free(opts.jindex); - close(sdp->path_fd); - cleanup_metafs(&mfs); +umount_meta: sync(); - + cleanup_metafs(&mfs); +close_sb: + close(sdp->path_fd); +out: if (!ret) print_results(&opts); diff --git a/gfs2/mkfs/main_jadd.c.bz1833141-2-gfs2_jadd_error_handling_overhaul b/gfs2/mkfs/main_jadd.c.bz1833141-2-gfs2_jadd_error_handling_overhaul new file mode 100644 index 0000000..c542480 --- /dev/null +++ b/gfs2/mkfs/main_jadd.c.bz1833141-2-gfs2_jadd_error_handling_overhaul @@ -0,0 +1,641 @@ +#include "clusterautoconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _(String) gettext(String) + +#include +#include +#include +#include "libgfs2.h" +#include "gfs2_mkfs.h" +#include "metafs.h" + +#define RANDOM(values) ((values) * (random() / (RAND_MAX + 1.0))) + +struct jadd_opts { + char *path; + char *new_inode; + char *per_node; + char *jindex; + unsigned orig_journals; + unsigned journals; + unsigned quiet:1; + unsigned debug:1; +}; + +#define JA_FL_SET 0 +#define JA_FL_CLEAR 1 +static void set_flags(int fd, int op, uint32_t flags) +{ + int err; + uint32_t val; + + err = ioctl(fd, FS_IOC_GETFLAGS, &val); + if (err) { + perror("GETFLAGS"); + exit(EXIT_FAILURE); + } + + if (op == JA_FL_SET) + val |= flags; + else if (op == JA_FL_CLEAR) + val &= ~flags; + + err = ioctl(fd, FS_IOC_SETFLAGS, &val); + if (err) { + perror("SETFLAGS"); + exit(EXIT_FAILURE); + } +} + +static int rename2system(struct jadd_opts *opts, const char *new_dir, const char *new_name) +{ + char *newpath; + int ret; + + if (asprintf(&newpath, "%s/%s", new_dir, new_name) < 0) { + perror(_("Failed to allocate new path")); + return -1; + } + + ret = rename(opts->new_inode, newpath); + free(newpath); + return ret; +} + +static int build_paths(const char *metafs_path, struct jadd_opts *opts) +{ + int i = 0; + struct { + char **path; + const char *tail; + } p[] = { + { &opts->new_inode, "new_inode" }, + { &opts->per_node, "per_node" }, + { &opts->jindex, "jindex" }, + { NULL, NULL} + }; + + while (p[i].path != NULL) { + if (asprintf(p[i].path, "%s/%s", metafs_path, p[i].tail) < 0) { + while (i > 0) + free(*p[--i].path); + return 1; + } + if (opts->debug) + printf("%d: %s\n", i, *p[i].path); + i++; + } + return 0; +} + +/** + * print_usage - print out usage information + * @prog_name: The name of this program + */ + +static void print_usage(const char *prog_name) +{ + int i; + const char *option, *param, *desc; + const char *options[] = { + /* Translators: This is a usage string printed with --help. + and here are the commandline parameters, + e.g. gfs2_jadd -j /dev/sda */ + "-c", "", _("Size of quota change file, in megabytes"), + "-D", NULL, _("Enable debugging code"), + "-h", NULL, _("Display this help, then exit"), + "-J", "", _("Size of journals, in megabytes"), + "-j", "", _("Number of journals"), + "-q", NULL, _("Don't print anything"), + "-V", NULL, _("Display version information, then exit"), + NULL, NULL, NULL /* Must be kept at the end */ + }; + + printf("%s\n", _("Usage:")); + printf("%s [%s] <%s>\n\n", prog_name, _("options"), _("device")); + printf(_("Adds journals to a GFS2 file system.")); + printf("\n\n%s\n", _("Options:")); + + for (i = 0; options[i] != NULL; i += 3) { + option = options[i]; + param = options[i+1]; + desc = options[i+2]; + printf("%3s %-15s %s\n", option, param ? param : "", desc); + } +} + +/** + * decode_arguments - decode command line arguments and fill in the struct gfs2_sbd + * @argc: + * @argv: + * @sdp: the decoded command line arguments + * + */ + +static void decode_arguments(int argc, char *argv[], struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + int cont = TRUE; + int optchar; + + while (cont) { + optchar = getopt(argc, argv, "c:DhJ:j:qu:V"); + + switch (optchar) { + case 'c': + sdp->qcsize = atoi(optarg); + break; + case 'D': + opts->debug = 1; + lgfs2_set_debug(1); + break; + case 'h': + print_usage(argv[0]); + exit(0); + break; + case 'J': + sdp->jsize = atoi(optarg); + break; + case 'j': + opts->journals = atoi(optarg); + break; + case 'q': + opts->quiet = 1; + break; + case 'V': + printf("gfs2_jadd %s (built %s %s)\n", VERSION, + __DATE__, __TIME__); + printf(REDHAT_COPYRIGHT "\n"); + exit(0); + break; + case ':': + case '?': + fprintf(stderr, _("Please use '-h' for help.\n")); + exit(EXIT_FAILURE); + break; + case EOF: + cont = FALSE; + break; + default: + die( _("Invalid option: %c\n"), optchar); + break; + }; + } + + if (optind < argc) { + opts->path = argv[optind]; + optind++; + } else + die( _("no path specified (try -h for help)\n")); + + if (optind < argc) + die( _("Unrecognized argument: %s\n"), argv[optind]); + + if (opts->debug) { + printf( _("Command line arguments:\n")); + printf(" qcsize = %u\n", sdp->qcsize); + printf(" jsize = %u\n", sdp->jsize); + printf(" journals = %u\n", sdp->md.journals); + printf(" quiet = %u\n", opts->quiet); + printf(" path = %s\n", opts->path); + } +} + +static void verify_arguments(struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + if (!opts->journals) + die( _("no journals specified\n")); + if (sdp->jsize < 32 || sdp->jsize > 1024) + die( _("bad journal size\n")); + if (!sdp->qcsize || sdp->qcsize > 64) + die( _("bad quota change size\n")); +} + +static void print_results(struct jadd_opts *opts) +{ + if (opts->debug) + printf("\n"); + else if (opts->quiet) + return; + + printf( _("Filesystem: %s\n"), opts->path); + printf( _("Old journals: %u\n"), opts->orig_journals); + printf( _("New journals: %u\n"), opts->journals); +} + +static int create_new_inode(struct jadd_opts *opts, uint64_t *addr) +{ + char *name = opts->new_inode; + int fd; + int error; + + for (;;) { + fd = open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600); + if (fd >= 0) + break; + if (errno == EEXIST) { + error = unlink(name); + if (error){ + perror("unlink"); + exit(EXIT_FAILURE); + } + } else{ + perror("create"); + exit(EXIT_FAILURE); + } + } + if (addr != NULL) { + struct stat st; + + fstat(fd, &st); + *addr = st.st_ino; + } + + return fd; +} + +static void add_ir(struct jadd_opts *opts) +{ + int fd; + char new_name[256]; + int error; + + fd = create_new_inode(opts, NULL); + + { + struct gfs2_inum_range ir; + + set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); + memset(&ir, 0, sizeof(struct gfs2_inum_range)); + if (write(fd, (void*)&ir, sizeof(struct gfs2_inum_range)) != + sizeof(struct gfs2_inum_range)) { + perror("add_ir"); + exit(EXIT_FAILURE); + } + } + + close(fd); + + sprintf(new_name, "inum_range%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_ir rename2system"); + exit(EXIT_FAILURE); + } +} + +static void add_sc(struct jadd_opts *opts) +{ + int fd; + char new_name[256]; + int error; + + fd = create_new_inode(opts, NULL); + + { + struct gfs2_statfs_change sc; + set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); + + memset(&sc, 0, sizeof(struct gfs2_statfs_change)); + if (write(fd, (void*)&sc, sizeof(struct gfs2_statfs_change)) != + sizeof(struct gfs2_statfs_change)) { + perror("add_sc"); + exit(EXIT_FAILURE); + } + } + + close(fd); + + sprintf(new_name, "statfs_change%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_sc rename2system"); + exit(EXIT_FAILURE); + } +} + +static void add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + int fd; + char new_name[256]; + int error; + + fd = create_new_inode(opts, NULL); + + { + char buf[sdp->bsize]; + unsigned int blocks = + sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift); + unsigned int x; + struct gfs2_meta_header mh; + + set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); + memset(buf, 0, sdp->bsize); + + for (x=0; xbsize) != sdp->bsize) { + perror("add_qc"); + exit(EXIT_FAILURE); + } + } + + lseek(fd, 0, SEEK_SET); + + memset(&mh, 0, sizeof(struct gfs2_meta_header)); + mh.mh_magic = GFS2_MAGIC; + mh.mh_type = GFS2_METATYPE_QC; + mh.mh_format = GFS2_FORMAT_QC; + gfs2_meta_header_out(&mh, buf); + + for (x=0; xbsize) != sdp->bsize) { + perror("add_qc"); + exit(EXIT_FAILURE); + } + } + + error = fsync(fd); + if (error){ + perror("add_qc fsync"); + exit(EXIT_FAILURE); + } + } + + close(fd); + + sprintf(new_name, "quota_change%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_qc rename2system"); + exit(EXIT_FAILURE); + } +} + +static void gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + struct statfs statbuf; + if (statfs(opts->path, &statbuf) < 0) { + perror(opts->path); + exit(EXIT_FAILURE); + } + sdp->bsize = statbuf.f_bsize; + sdp->blks_total = statbuf.f_blocks; + sdp->blks_alloced = sdp->blks_total - statbuf.f_bfree; +} + +static void find_current_journals(struct jadd_opts *opts) +{ + struct dirent *dp; + DIR *dirp; + unsigned existing_journals = 0; + + dirp = opendir(opts->jindex); + if (!dirp) { + perror("jindex"); + exit(EXIT_FAILURE); + } + while (dirp) { + if ((dp = readdir(dirp)) != NULL) { + if (strncmp(dp->d_name, "journal", 7) == 0) + existing_journals++; + } else + goto close; + } +close: + closedir(dirp); + if (existing_journals == 0) { + die( _("No journals found. Did you run mkfs.gfs2 correctly?\n")); + } + + opts->orig_journals = existing_journals; +} + +#ifdef GFS2_HAS_LH_V2 +static uint64_t find_block_address(int fd, off_t offset, unsigned bsize) +{ + struct { + struct fiemap fm; + struct fiemap_extent fe; + } fme; + int ret; + + fme.fm.fm_start = offset; + fme.fm.fm_length = 1; + fme.fm.fm_flags = FIEMAP_FLAG_SYNC; + fme.fm.fm_extent_count = 1; + + ret = ioctl(fd, FS_IOC_FIEMAP, &fme.fm); + if (ret != 0 || fme.fm.fm_mapped_extents != 1) { + fprintf(stderr, "Failed to find log header block address\n"); + return 0; + } + return fme.fe.fe_physical / bsize; +} +#endif + +static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + int fd; + char new_name[256]; + int error; + uint64_t addr; + + fd = create_new_inode(opts, &addr); + + { + char buf[sdp->bsize]; + unsigned int blocks = + sdp->jsize << (20 - sdp->sd_sb.sb_bsize_shift); + unsigned int x; + struct gfs2_log_header lh; + uint64_t seq = RANDOM(blocks); + off_t off = 0; + + set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); + memset(buf, 0, sdp->bsize); + for (x=0; xbsize) != sdp->bsize) { + perror("add_j"); + exit(EXIT_FAILURE); + } + } + + lseek(fd, 0, SEEK_SET); + + memset(&lh, 0, sizeof(struct gfs2_log_header)); + lh.lh_header.mh_magic = GFS2_MAGIC; + lh.lh_header.mh_type = GFS2_METATYPE_LH; + lh.lh_header.mh_format = GFS2_FORMAT_LH; + lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT; +#ifdef GFS2_HAS_LH_V2 + lh.lh_flags |= GFS2_LOG_HEAD_USERSPACE; + lh.lh_jinode = addr; +#endif + for (x=0; xlh_hash = cpu_to_be32(hash); +#ifdef GFS2_HAS_LH_V2 + ((struct gfs2_log_header *)buf)->lh_addr = cpu_to_be64( + find_block_address(fd, off, sdp->bsize)); + hash = lgfs2_log_header_crc(buf, sdp->bsize); + ((struct gfs2_log_header *)buf)->lh_crc = cpu_to_be32(hash); +#endif + if (write(fd, buf, sdp->bsize) != sdp->bsize) { + perror("add_j"); + exit(EXIT_FAILURE); + } + + if (++seq == blocks) + seq = 0; + off += sdp->bsize; + } + + error = fsync(fd); + if (error){ + perror("add_j fsync"); + exit(EXIT_FAILURE); + } + } + + close(fd); + + sprintf(new_name, "journal%u", opts->journals); + error = rename2system(opts, opts->jindex, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_j rename2system"); + exit(EXIT_FAILURE); + } +} + +static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) +{ + /* Compute how much space we'll need for the new journals + * Number of blocks needed per added journal: + * 1 block for the ir inode + * 1 block for the sc inode + * for sizes of the qc and journal inodes, use lgfs2_space_for_data() + * to calculate. + */ + uint64_t blks_per_j, total_blks; + + blks_per_j = 1 + 1 + + lgfs2_space_for_data(sdp, sdp->bsize, sdp->qcsize << 20) + + lgfs2_space_for_data(sdp, sdp->bsize, sdp->jsize << 20); + total_blks = opts->journals * blks_per_j; + + if (total_blks > (sdp->blks_total - sdp->blks_alloced)) { + printf( _("\nInsufficient space on the device to add %u %uMB " + "journals (%uMB QC size)\n\n"), + opts->journals, sdp->jsize, sdp->qcsize); + printf( _("Required space : %*lu blks (%lu blks per " + "journal)\n"), 10, total_blks, blks_per_j); + printf( _("Available space : %*lu blks\n\n"), 10, + sdp->blks_total - sdp->blks_alloced); + errno = ENOSPC; + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + struct jadd_opts opts = {0}; + struct gfs2_sbd sbd, *sdp = &sbd; + struct metafs mfs = {0}; + struct mntent *mnt; + unsigned int total, ret = 0; + + setlocale(LC_ALL, ""); + textdomain("gfs2-utils"); + srandom(time(NULL) ^ getpid()); + + memset(sdp, 0, sizeof(struct gfs2_sbd)); + sdp->jsize = GFS2_DEFAULT_JSIZE; + sdp->qcsize = GFS2_DEFAULT_QCSIZE; + opts.journals = 1; + + decode_arguments(argc, argv, sdp, &opts); + verify_arguments(sdp, &opts); + + sbd.path_fd = lgfs2_open_mnt_dir(opts.path, O_RDONLY|O_CLOEXEC, &mnt); + if (sbd.path_fd < 0) { + fprintf(stderr, _("Error looking up mount '%s': %s\n"), opts.path, strerror(errno)); + exit(EXIT_FAILURE); + } + if (mnt == NULL) { + fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), opts.path); + exit(EXIT_FAILURE); + } + gather_info(sdp, &opts); + mfs.context = copy_context_opt(mnt); + if (mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug)) { + perror("GFS2 metafs"); + exit(EXIT_FAILURE); + } + + if (build_paths(mfs.path, &opts)) { + perror(_("Failed to build paths")); + exit(EXIT_FAILURE); + } + + if (compute_constants(sdp)) { + perror(_("Failed to compute file system constants")); + exit(EXIT_FAILURE); + } + find_current_journals(&opts); + + ret = check_fit(sdp, &opts); + if (ret) { + perror(_("Failed to add journals")); + goto out; + } + + total = opts.orig_journals + opts.journals; + for (opts.journals = opts.orig_journals; + opts.journals < total; + opts.journals++) { + if (metafs_interrupted) { + cleanup_metafs(&mfs); + exit(130); + } + add_ir(&opts); + add_sc(&opts); + add_qc(sdp, &opts); + add_j(sdp, &opts); + } + +out: + free(opts.new_inode); + free(opts.per_node); + free(opts.jindex); + close(sdp->path_fd); + cleanup_metafs(&mfs); + sync(); + + if (!ret) + print_results(&opts); + + return ret; +}