From 0193cbaea40287c40974f8e03faf28741078869b Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 04 2020 09:57:38 +0000 Subject: Apply patch bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size.patch patch_name: bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size.patch present_in_specfile: true --- diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c index 846b341..412d470 100644 --- a/gfs2/mkfs/main_mkfs.c +++ b/gfs2/mkfs/main_mkfs.c @@ -505,7 +505,7 @@ static unsigned choose_blocksize(struct mkfs_opts *opts) } if (!opts->got_bsize && got_topol) { if (dev->optimal_io_size <= getpagesize() && - dev->optimal_io_size >= dev->minimum_io_size) + dev->optimal_io_size >= GFS2_DEFAULT_BSIZE) bsize = dev->optimal_io_size; else if (dev->physical_sector_size <= getpagesize() && dev->physical_sector_size >= GFS2_DEFAULT_BSIZE) diff --git a/gfs2/mkfs/main_mkfs.c.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size b/gfs2/mkfs/main_mkfs.c.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size new file mode 100644 index 0000000..846b341 --- /dev/null +++ b/gfs2/mkfs/main_mkfs.c.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size @@ -0,0 +1,1189 @@ +#include "clusterautoconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _(String) gettext(String) + +#include +#include "libgfs2.h" +#include "gfs2_mkfs.h" +#include "progress.h" + +#ifdef GFS2_HAS_UUID +#include +#endif + +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. mkfs.gfs2 -b -j /dev/sda */ + "-b", _(""), _("File system block size, in bytes"), + "-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"), + "-K", NULL, _("Don't try to discard unused blocks"), + "-O", NULL, _("Don't ask for confirmation"), + "-o", _("[=][,...]"), _("Specify extended options. See '-o help'."), + "-p", _(""), _("Name of the locking protocol"), + "-q", NULL, _("Don't print anything"), + "-r", _(""), _("Size of resource groups, in megabytes"), + "-t", _(""), _("Name of the lock table"), + "-V", NULL, _("Display program version information, then exit"), + NULL, NULL, NULL /* Must be kept at the end */ + }; + + printf("%s\n", _("Usage:")); + printf("%s [%s] <%s> [%s]\n\n", prog_name, _("options"), _("device"), _("size")); + printf(_("Create a gfs2 file system on a device. If a size, in blocks, is not " + "specified, the whole device will be used.")); + 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 %-22s %s\n", option, param ? param : "", desc); + } +} + +static void print_ext_opts(void) +{ + int i; + const char *options[] = { + "help", _("Display this help, then exit"), + "swidth=N", _("Specify the stripe width of the device, overriding probed values"), + "sunit=N", _("Specify the stripe unit of the device, overriding probed values"), + "align=[0|1]", _("Disable or enable alignment of resource groups"), + NULL, NULL + }; + printf(_("Extended options:\n")); + for (i = 0; options[i] != NULL; i += 2) { + printf("%15s %-22s\n", options[i], options[i + 1]); + } +} + +/** + * Values probed by libblkid: + * alignment_offset: offset, in bytes, of the start of the dev from its natural alignment + * logical_sector_size: smallest addressable unit + * minimum_io_size: device's preferred unit of I/O. RAID stripe unit. + * optimal_io_size: biggest I/O we can submit without incurring a penalty. RAID stripe width. + * physical_sector_size: the smallest unit we can write atomically + */ +struct mkfs_dev { + int fd; + const char *path; + struct stat stat; + uint64_t size; + unsigned long alignment_offset; + unsigned long logical_sector_size; + unsigned long minimum_io_size; + unsigned long optimal_io_size; + unsigned long physical_sector_size; + + unsigned int got_topol:1; +}; + +struct mkfs_opts { + unsigned bsize; + unsigned qcsize; + unsigned jsize; + unsigned rgsize; + unsigned long sunit; + unsigned long swidth; + uint64_t fssize; + uint32_t journals; + const char *lockproto; + const char *locktable; + struct mkfs_dev dev; + unsigned discard:1; + + unsigned got_bsize:1; + unsigned got_qcsize:1; + unsigned got_jsize:1; + unsigned got_rgsize:1; + unsigned got_sunit:1; + unsigned got_swidth:1; + unsigned got_fssize:1; + unsigned got_journals:1; + unsigned got_lockproto:1; + unsigned got_locktable:1; + unsigned got_device:1; + unsigned got_topol:1; + + unsigned override:1; + unsigned quiet:1; + unsigned debug:1; + unsigned confirm:1; + unsigned align:1; +}; + +static void opts_init(struct mkfs_opts *opts) +{ + memset(opts, 0, sizeof(*opts)); + opts->discard = 1; + opts->journals = 1; + opts->bsize = GFS2_DEFAULT_BSIZE; + opts->jsize = GFS2_DEFAULT_JSIZE; + opts->qcsize = GFS2_DEFAULT_QCSIZE; + opts->rgsize = GFS2_DEFAULT_RGSIZE; + opts->lockproto = "lock_dlm"; + opts->locktable = ""; + opts->confirm = 1; + opts->align = 1; +} + +struct gfs2_inum *mkfs_journals = NULL; + +#ifndef BLKDISCARD +#define BLKDISCARD _IO(0x12,119) +#endif + +static int discard_blocks(int fd, uint64_t len, int debug) +{ + __uint64_t range[2]; + + range[0] = 0; + range[1] = len; + if (debug) + /* Translators: "discard" is a request sent to a storage device to + * discard a range of blocks. */ + printf(_("Issuing discard request: range: %llu - %llu..."), + (unsigned long long)range[0], + (unsigned long long)range[1]); + if (ioctl(fd, BLKDISCARD, &range) < 0) { + if (debug) + printf("%s = %d\n", _("error"), errno); + return errno; + } + if (debug) + printf(_("Successful.\n")); + return 0; +} + +/** + * Convert a human-readable size string to a long long. + * Copied and adapted from xfs_mkfs.c. + */ +static long long cvtnum(unsigned int blocksize, unsigned int sectorsize, const char *s) +{ + long long i; + char *sp; + + i = strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return -1LL; + if (*sp == '\0') + return i; + + *sp = tolower(*sp); + if (*sp == 'b' && sp[1] == '\0') { + if (blocksize) + return i * blocksize; + fprintf(stderr, _("Block size not available yet.\n")); + exit(1); + } + if (*sp == 's' && sp[1] == '\0') { + if (sectorsize) + return i * sectorsize; + return i * GFS2_BASIC_BLOCK; + } + if (*sp == 'k' && sp[1] == '\0') + return 1024LL * i; + if (*sp == 'm' && sp[1] == '\0') + return 1024LL * 1024LL * i; + if (*sp == 'g' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * i; + if (*sp == 't' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * 1024LL * i; + if (*sp == 'p' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * i; + if (*sp == 'e' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * i; + return -1LL; +} + +static unsigned long parse_ulong(struct mkfs_opts *opts, const char *key, const char *val) +{ + long long l; + if (val == NULL || *val == '\0') { + fprintf(stderr, _("Missing argument to '%s'\n"), key); + exit(-1); + } + l = cvtnum(opts->bsize, 0, val); + if (l > ULONG_MAX || l < 0) { + fprintf(stderr, _("Value of '%s' is invalid\n"), key); + exit(-1); + } + return (unsigned long)l; +} + +static unsigned parse_bool(struct mkfs_opts *opts, const char *key, const char *val) +{ + if (strnlen(val, 2) == 1) { + if (*val == '0') + return 0; + if (*val == '1') + return 1; + } + fprintf(stderr, _("Option '%s' must be either 1 or 0\n"), key); + exit(-1); +} + +static int parse_topology(struct mkfs_opts *opts, char *str) +{ + char *opt; + unsigned i = 0; + unsigned long *topol[5] = { + &opts->dev.alignment_offset, + &opts->dev.logical_sector_size, + &opts->dev.minimum_io_size, + &opts->dev.optimal_io_size, + &opts->dev.physical_sector_size + }; + + while ((opt = strsep(&str, ":")) != NULL) { + if (i > 4) { + fprintf(stderr, "Too many topology values.\n"); + return 1; + } + *topol[i] = parse_ulong(opts, "test_topology", opt); + i++; + } + if (i < 5) { + fprintf(stderr, "Too few topology values.\n"); + return 1; + } + return 0; +} + +static void opt_parse_extended(char *str, struct mkfs_opts *opts) +{ + char *opt; + while ((opt = strsep(&str, ",")) != NULL) { + char *key = strsep(&opt, "="); + char *val = strsep(&opt, "="); + if (key == NULL || *key == '\0') { + fprintf(stderr, _("Missing argument to '-o' option\n")); + exit(-1); + } + if (strcmp("sunit", key) == 0) { + opts->sunit = parse_ulong(opts, "sunit", val); + opts->got_sunit = 1; + } else if (strcmp("swidth", key) == 0) { + opts->swidth = parse_ulong(opts, "swidth", val); + opts->got_swidth = 1; + } else if (strcmp("align", key) == 0) { + opts->align = parse_bool(opts, "align", val); + } else if (strcmp("test_topology", key) == 0) { + if (parse_topology(opts, val) != 0) + exit(-1); + opts->got_topol = (opts->dev.logical_sector_size != 0 && + opts->dev.physical_sector_size != 0); + } else if (strcmp("help", key) == 0) { + print_ext_opts(); + exit(0); + } else { + fprintf(stderr, _("Invalid option '%s'\n"), key); + exit(-1); + } + } +} + +static void opts_get(int argc, char *argv[], struct mkfs_opts *opts) +{ + int c; + while (1) { + c = getopt(argc, argv, "-b:c:DhJ:j:KOo:p:qr:t:V"); + if (c == -1) + break; + + switch (c) { + case 'b': + opts->bsize = atoi(optarg); + opts->got_bsize = 1; + break; + case 'c': + opts->qcsize = atoi(optarg); + opts->got_qcsize = 1; + break; + case 'D': + opts->debug = 1; + lgfs2_set_debug(1); + break; + case 'h': + print_usage(argv[0]); + exit(0); + case 'J': + opts->jsize = atoi(optarg); + opts->got_jsize = 1; + break; + case 'j': + opts->journals = atoi(optarg); + opts->got_journals = 1; + break; + case 'K': + opts->discard = 0; + break; + case 'O': + opts->override = 1; + break; + case 'p': + opts->lockproto = optarg; + opts->got_lockproto = 1; + break; + case 't': + opts->locktable = optarg; + opts->got_locktable = 1; + break; + case 'q': + opts->quiet = 1; + break; + case 'r': + opts->rgsize = atoi(optarg); + opts->got_rgsize = 1; + break; + case 'o': + opt_parse_extended(optarg, opts); + break; + case 'V': + printf("mkfs.gfs2 %s (built %s %s)\n", VERSION, + __DATE__, __TIME__); + printf(REDHAT_COPYRIGHT "\n"); + exit(EXIT_SUCCESS); + break; + case ':': + case '?': + fprintf(stderr, _("Please use '-h' for help.\n")); + exit(EXIT_FAILURE); + break; + case 1: + if (strcmp(optarg, "gfs2") == 0) + continue; + if (!opts->got_device) { + opts->dev.path = optarg; + opts->got_device = 1; + } else if (!opts->got_fssize && isdigit(optarg[0])) { + opts->fssize = atol(optarg); + opts->got_fssize = 1; + } else + die( _("More than one device specified (try -h for help)\n")); + break; + default: + die( _("Invalid option: %c\n"), c); + break; + }; + } +} + +/** + * test_locking - Make sure the GFS2 is set up to use the right lock protocol + * @lockproto: the lock protocol to mount + * @locktable: the locktable name + * + */ + +static void test_locking(struct mkfs_opts *opts) +{ + const char *c; + /* Translators: A lock table is a string identifying a gfs2 file system + * in a cluster, e.g. cluster_name:fs_name */ + const char *errprefix = _("Invalid lock table:"); + int table_required = (strcmp(opts->lockproto, "lock_gulm") == 0) + || (strcmp(opts->lockproto, "lock_dlm") == 0); + + if ((strcmp(opts->lockproto, "lock_nolock") != 0) && !table_required) + die( _("Invalid lock protocol: %s\n"), opts->lockproto); + + /* When lock_*lm is given as the lock protocol, require a lock table too */ + if (!opts->got_locktable) { + if (table_required) { + fprintf(stderr, _("No lock table specified.\n")); + exit(-1); + } + return; + } + /* User gave a lock table option, validate it */ + if (*opts->locktable == '\0') { + fprintf(stderr, _("Lock table is empty.\n")); + exit(-1); + } + for (c = opts->locktable; *c; c++) { + if (!isalnum(*c) && (*c != '-') && (*c != '_') && (*c != ':')) + die("%s %s '%c'\n", errprefix, _("invalid character"), *c); + } + c = strstr(opts->locktable, ":"); + if (!c) + die("%s %s\n", errprefix, _("missing colon")); + + if (c == opts->locktable) + die("%s %s\n", errprefix, _("cluster name is missing")); + if (c - opts->locktable > 32) + die("%s %s\n", errprefix, _("cluster name is too long")); + + c++; + if (strstr(c, ":")) + die("%s %s\n", errprefix, _("contains more than one colon")); + if (!strlen(c)) + die("%s %s\n", errprefix, _("file system name is missing")); + if (strlen(c) > 30) + die("%s %s\n", errprefix, _("file system name is too long")); +} + +static void are_you_sure(void) +{ + while (1) { + char *line = NULL; + size_t len = 0; + int ret; + int res; + + /* Translators: We use rpmatch(3) to match the answers to y/n + questions in the user's own language, so the [y/n] here must also be + translated to match one of the letters in the pattern printed by + `locale -k yesexpr` and one of the letters in the pattern printed by + `locale -k noexpr` */ + printf( _("Are you sure you want to proceed? [y/n] ")); + ret = getline(&line, &len, stdin); + res = rpmatch(line); + free(line); + if (ret <= 0) + continue; + if (res == 1) /* Yes */ + return; + if (res == 0) /* No */ + exit(1); + /* Unrecognized input; go again. */ + }; +} + +static unsigned choose_blocksize(struct mkfs_opts *opts) +{ + unsigned int x; + unsigned int bsize = opts->bsize; + struct mkfs_dev *dev = &opts->dev; + int got_topol = (dev->got_topol || opts->got_topol); + + if (got_topol && opts->debug) { + printf("alignment_offset: %lu\n", dev->alignment_offset); + printf("logical_sector_size: %lu\n", dev->logical_sector_size); + printf("minimum_io_size: %lu\n", dev->minimum_io_size); + printf("optimal_io_size: %lu\n", dev->optimal_io_size); + printf("physical_sector_size: %lu\n", dev->physical_sector_size); + } + if (got_topol && dev->alignment_offset != 0) { + fprintf(stderr, + _("Warning: device is not properly aligned. This may harm performance.\n")); + dev->physical_sector_size = dev->logical_sector_size; + } + if (!opts->got_bsize && got_topol) { + if (dev->optimal_io_size <= getpagesize() && + dev->optimal_io_size >= dev->minimum_io_size) + bsize = dev->optimal_io_size; + else if (dev->physical_sector_size <= getpagesize() && + dev->physical_sector_size >= GFS2_DEFAULT_BSIZE) + bsize = dev->physical_sector_size; + } + + /* Block sizes must be a power of two from 512 to 65536 */ + for (x = 512; x; x <<= 1) + if (x == bsize) + break; + + if (!x || bsize > getpagesize()) + die( _("Block size must be a power of two between 512 and %d\n"), + getpagesize()); + + if (bsize < dev->logical_sector_size) { + die( _("Error: Block size %d is less than minimum logical " + "block size (%lu).\n"), bsize, dev->logical_sector_size); + } + + if (bsize < dev->physical_sector_size) { + printf( _("Warning: Block size %d is inefficient because it " + "is less than the physical block size (%lu).\n"), + bsize, dev->physical_sector_size); + opts->confirm = 1; + } + return bsize; +} + +static void opts_check(struct mkfs_opts *opts) +{ + if (!opts->got_device) { + fprintf(stderr, _("No device specified. Use -h for help\n")); + exit(1); + } + + test_locking(opts); + + if (GFS2_MIN_RGSIZE > opts->rgsize || opts->rgsize > GFS2_MAX_RGSIZE) + /* Translators: gfs2 file systems are split into equal sized chunks called + resource groups. We're checking that the user gave a valid size for them. */ + die( _("bad resource group size\n")); + + if (!opts->journals) + die( _("no journals specified\n")); + + if (opts->jsize < GFS2_MIN_JSIZE || opts->jsize > GFS2_MAX_JSIZE) + die( _("bad journal size\n")); + + if (!opts->qcsize || opts->qcsize > 64) + die( _("bad quota change size\n")); + + if ((opts->got_sunit && !opts->got_swidth) || (!opts->got_sunit && opts->got_swidth)) { + fprintf(stderr, _("Stripe unit and stripe width must be specified together\n")); + exit(1); + } +} + +static void print_results(struct gfs2_sb *sb, struct mkfs_opts *opts, uint64_t rgrps, uint64_t fssize) +{ + printf("%-27s%s\n", _("Device:"), opts->dev.path); + printf("%-27s%u\n", _("Block size:"), sb->sb_bsize); + printf("%-27s%.2f %s (%"PRIu64" %s)\n", _("Device size:"), + /* Translators: "GB" here means "gigabytes" */ + (opts->dev.size / ((float)(1 << 30))), _("GB"), + (opts->dev.size / sb->sb_bsize), _("blocks")); + printf("%-27s%.2f %s (%"PRIu64" %s)\n", _("Filesystem size:"), + (fssize / ((float)(1 << 30)) * sb->sb_bsize), _("GB"), fssize, _("blocks")); + printf("%-27s%u\n", _("Journals:"), opts->journals); + printf("%-27s%uMB\n", _("Journal size:"), opts->jsize); + printf("%-27s%"PRIu64"\n", _("Resource groups:"), rgrps); + printf("%-27s\"%s\"\n", _("Locking protocol:"), opts->lockproto); + printf("%-27s\"%s\"\n", _("Lock table:"), opts->locktable); +#ifdef GFS2_HAS_UUID + { + char readable_uuid[36+1]; + + uuid_unparse(sb->sb_uuid, readable_uuid); + /* Translators: "UUID" = universally unique identifier. */ + printf("%-27s%s\n", _("UUID:"), readable_uuid); + } +#endif +} + +static void warn_of_destruction(const char *path) +{ + struct stat lnkstat; + char *abspath = NULL; + + if (lstat(path, &lnkstat) == -1) { + perror(_("Failed to lstat the device")); + exit(EXIT_FAILURE); + } + if (S_ISLNK(lnkstat.st_mode)) { + abspath = canonicalize_file_name(path); + if (abspath == NULL) { + perror(_("Could not find the absolute path of the device")); + exit(EXIT_FAILURE); + } + /* Translators: Example: "/dev/vg/lv is a symbolic link to /dev/dm-2" */ + printf( _("%s is a symbolic link to %s\n"), path, abspath); + path = abspath; + } + printf(_("This will destroy any data on %s\n"), path); + free(abspath); +} + +static int zero_gap(struct gfs2_sbd *sdp, uint64_t addr, size_t blocks) +{ + struct iovec *iov; + char *zerobuf; + ssize_t wrote; + unsigned i; + + if (blocks == 0) + return 0; + iov = calloc(blocks, sizeof(*iov)); + if (iov == NULL) { + perror(_("Failed to zero blocks\n")); + return 1; + } + zerobuf = calloc(1, sdp->bsize); + if (zerobuf == NULL) { + perror(_("Failed to zero blocks\n")); + free(iov); + return 1; + } + for (i = 0; i < blocks; i++) { + iov[i].iov_base = zerobuf; + iov[i].iov_len = sdp->bsize; + } + wrote = pwritev(sdp->device_fd, iov, blocks, addr * sdp->bsize); + if (wrote != blocks * sdp->bsize) { + fprintf(stderr, _("Zeroing write failed at block %"PRIu64"\n"), addr); + free(zerobuf); + free(iov); + return 1; + } + free(zerobuf); + free(iov); + return 0; +} + +static lgfs2_rgrps_t rgs_init(struct mkfs_opts *opts, struct gfs2_sbd *sdp) +{ + lgfs2_rgrps_t rgs; + uint64_t al_base = 0; + uint64_t al_off = 0; + + if (opts->align && opts->got_sunit) { + if ((opts->sunit % sdp->bsize) != 0) { + fprintf(stderr, _("Stripe unit (%lu) must be a multiple of block size (%u)\n"), + opts->sunit, sdp->bsize); + exit(1); + } else if ((opts->swidth % opts->sunit) != 0) { + fprintf(stderr, _("Stripe width (%lu) must be a multiple of stripe unit (%lu)\n"), + opts->swidth, opts->sunit); + exit(1); + } else { + al_base = opts->swidth / sdp->bsize; + al_off = opts->sunit / sdp->bsize; + } + } else if (opts->align) { + if (opts->dev.optimal_io_size <= opts->dev.physical_sector_size || + opts->dev.minimum_io_size <= opts->dev.physical_sector_size || + (opts->dev.optimal_io_size % opts->dev.minimum_io_size) != 0) { + /* If optimal_io_size is not a multiple of minimum_io_size then + the values are not reliable swidth and sunit values, so disable + rgrp alignment */ + opts->align = 0; + } else { + al_base = opts->dev.optimal_io_size / sdp->bsize; + al_off = opts->dev.minimum_io_size / sdp->bsize; + } + } + + rgs = lgfs2_rgrps_init(sdp, al_base, al_off); + if (rgs == NULL) { + perror(_("Could not initialise resource groups")); + exit(-1); + } + + if (opts->debug) { + printf(" rgrp align = "); + if (opts->align) + printf("%"PRIu64"+%"PRIu64" blocks\n", al_base, al_off); + else + printf("(disabled)\n"); + } + + return rgs; +} + +static int place_rgrp(struct gfs2_sbd *sdp, lgfs2_rgrp_t rg, int debug) +{ + uint64_t prev_end = (GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sdp->bsize) + 1; + const struct gfs2_rindex *ri = lgfs2_rgrp_index(rg); + lgfs2_rgrp_t prev = lgfs2_rgrp_prev(rg); + int err = 0; + + if (prev != NULL) { + prev_end = lgfs2_rgrp_index(prev)->ri_data0 + + lgfs2_rgrp_index(prev)->ri_data; + } + err = zero_gap(sdp, prev_end, ri->ri_addr - prev_end); + if (err != 0) + return -1; + err = lgfs2_rgrp_write(sdp->device_fd, rg); + if (err != 0) { + perror(_("Failed to write resource group")); + return -1; + } + if (debug) { + gfs2_rindex_print(ri); + printf("\n"); + } + sdp->blks_total += ri->ri_data; + sdp->fssize = ri->ri_data0 + ri->ri_data; + sdp->rgrps++; + return 0; +} + +static int add_rgrp(lgfs2_rgrps_t rgs, uint64_t *addr, uint32_t len, lgfs2_rgrp_t *rg) +{ + struct gfs2_rindex ri; + uint64_t nextaddr; + + /* When we get to the end of the device, it's only an error if we have + more structures left to write, i.e. when len is != 0. */ + nextaddr = lgfs2_rindex_entry_new(rgs, &ri, *addr, len); + if (nextaddr == 0) { + if (len != 0) { + perror(_("Failed to create resource group index entry")); + return -1; + } else { + return 1; + } + } + *rg = lgfs2_rgrps_append(rgs, &ri, nextaddr - *addr); + if (*rg == NULL) { + perror(_("Failed to create resource group")); + return -1; + } + *addr = nextaddr; + return 0; +} + +static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts, uint64_t *rgaddr) +{ + struct gfs2_progress_bar progress; + uint64_t jfsize = lgfs2_space_for_data(sdp, sdp->bsize, opts->jsize << 20); + uint32_t rgsize = lgfs2_rgsize_for_data(jfsize, sdp->bsize); + unsigned j; + + gfs2_progress_init(&progress, opts->journals, _("Adding journals: "), opts->quiet); + + /* We'll build the jindex later so remember where we put the journals */ + mkfs_journals = calloc(opts->journals, sizeof(*mkfs_journals)); + if (mkfs_journals == NULL) + return 1; + *rgaddr = lgfs2_rgrp_align_addr(rgs, LGFS2_SB_ADDR(sdp) + 1); + rgsize = lgfs2_rgrp_align_len(rgs, rgsize); + + for (j = 0; j < opts->journals; j++) { + int result; + lgfs2_rgrp_t rg; + struct gfs2_inode in = {0}; + + gfs2_progress_update(&progress, (j + 1)); + + if (opts->debug) + printf(_("Placing resource group for journal%u\n"), j); + + result = add_rgrp(rgs, rgaddr, rgsize, &rg); + if (result > 0) + break; + else if (result < 0) + return result; + + result = lgfs2_rgrp_bitbuf_alloc(rg); + if (result != 0) { + perror(_("Failed to allocate space for bitmap buffer")); + return result; + } + /* Allocate at the beginning of the rgrp, bypassing extent search */ + in.i_di.di_num.no_addr = lgfs2_rgrp_index(rg)->ri_data0; + /* In order to keep writes sequential here, we have to allocate + the journal, then write the rgrp header (which is now in its + final form) and then write the journal out */ + result = lgfs2_file_alloc(rg, opts->jsize << 20, &in, GFS2_DIF_SYSTEM, S_IFREG | 0600); + if (result != 0) { + fprintf(stderr, _("Failed to allocate space for journal %u\n"), j); + return result; + } + + if (opts->debug) + gfs2_dinode_print(&in.i_di); + + result = place_rgrp(sdp, rg, opts->debug); + if (result != 0) + return result; + + lgfs2_rgrp_bitbuf_free(rg); + + result = lgfs2_write_filemeta(&in); + if (result != 0) { + fprintf(stderr, _("Failed to write journal %u\n"), j); + return result; + } + + result = lgfs2_write_journal_data(&in); + if (result != 0) { + fprintf(stderr, _("Failed to write data blocks for journal %u\n"), j); + return result; + } + mkfs_journals[j] = in.i_di.di_num; + } + gfs2_progress_close(&progress, _("Done\n")); + + return 0; +} + +static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, uint64_t *rgaddr, struct mkfs_opts *opts) +{ + struct gfs2_progress_bar progress; + uint32_t rgblks = ((opts->rgsize << 20) / sdp->bsize); + uint32_t rgnum; + int result; + + rgnum = lgfs2_rgrps_plan(rgs, sdp->device.length - *rgaddr, rgblks); + gfs2_progress_init(&progress, (rgnum + opts->journals), _("Building resource groups: "), opts->quiet); + + while (1) { + lgfs2_rgrp_t rg; + result = add_rgrp(rgs, rgaddr, 0, &rg); + if (result > 0) + break; + else if (result < 0) + return result; + + result = place_rgrp(sdp, rg, opts->debug); + if (result != 0) { + fprintf(stderr, _("Failed to build resource groups\n")); + return result; + } + + gfs2_progress_update(&progress, (sdp->rgrps)); + } + gfs2_progress_close(&progress, _("Done\n")); + posix_fadvise(sdp->device_fd, 0, sdp->fssize * sdp->bsize, POSIX_FADV_DONTNEED); + + return 0; +} + +/* + * Find a reasonable journal file size (in blocks) given the number of blocks + * in the filesystem. For very small filesystems, it is not reasonable to + * have a journal that fills more than half of the filesystem. + * + * n.b. comments assume 4k blocks + * + * This was copied and adapted from e2fsprogs. + */ +static int default_journal_size(unsigned bsize, uint64_t num_blocks) +{ + int min_blocks = (GFS2_MIN_JSIZE << 20) / bsize; + + if (num_blocks < 2 * min_blocks) + return -1; + if (num_blocks < 131072) /* 512 MB */ + return min_blocks; /* 8 MB */ + if (num_blocks < 512*1024) /* 2 GB */ + return (4096); /* 16 MB */ + if (num_blocks < 2048*1024) /* 8 GB */ + return (8192); /* 32 MB */ + if (num_blocks < 4096*1024) /* 16 GB */ + return (16384); /* 64 MB */ + if (num_blocks < 262144*1024) /* 1 TB */ + return (32768); /* 128 MB */ + if (num_blocks < 2621440UL*1024) /* 10 TB */ + return (131072); /* 512 MB */ + return 262144; /* 1 GB */ +} + +static void sbd_init(struct gfs2_sbd *sdp, struct mkfs_opts *opts, unsigned bsize) +{ + memset(sdp, 0, sizeof(struct gfs2_sbd)); + sdp->time = time(NULL); + sdp->rgtree.osi_node = NULL; + sdp->rgsize = opts->rgsize; + sdp->qcsize = opts->qcsize; + sdp->jsize = opts->jsize; + sdp->md.journals = opts->journals; + sdp->device_fd = opts->dev.fd; + sdp->bsize = sdp->sd_sb.sb_bsize = bsize; + + if (compute_constants(sdp)) { + perror(_("Failed to compute file system constants")); + exit(1); + } + sdp->device.length = opts->dev.size / sdp->bsize; + if (opts->got_fssize) { + if (opts->fssize > sdp->device.length) { + fprintf(stderr, _("Specified size is bigger than the device.")); + die("%s %.2f %s (%"PRIu64" %s)\n", _("Device size:"), + opts->dev.size / ((float)(1 << 30)), _("GB"), + opts->dev.size / sdp->bsize, _("blocks")); + } + sdp->device.length = opts->fssize; + } + /* opts->jsize has already been max/min checked but we need to check it + makes sense for the device size, or set a sensible default, if one + will fit. For user-provided journal sizes, limit it to half of the fs. */ + if (!opts->got_jsize) { + int default_jsize = default_journal_size(sdp->bsize, sdp->device.length / opts->journals); + if (default_jsize < 0) { + fprintf(stderr, _("gfs2 will not fit on this device.\n")); + exit(1); + } + opts->jsize = (default_jsize * sdp->bsize) >> 20; + } else if ((((opts->jsize * opts->journals) << 20) / sdp->bsize) > (sdp->device.length / 2)) { + unsigned max_jsize = (sdp->device.length / 2 * sdp->bsize / opts->journals) >> 20; + + fprintf(stderr, _("gfs2 will not fit on this device.\n")); + if (max_jsize >= GFS2_MIN_JSIZE) + fprintf(stderr, _("Maximum size for %u journals on this device is %uMB.\n"), + opts->journals, max_jsize); + exit(1); + } + sdp->jsize = opts->jsize; +} + +static int probe_contents(struct mkfs_dev *dev) +{ + int ret; + const char *contents; + blkid_probe pr = blkid_new_probe(); + if (pr == NULL || blkid_probe_set_device(pr, dev->fd, 0, 0) != 0 + || blkid_probe_enable_superblocks(pr, TRUE) != 0 + || blkid_probe_enable_partitions(pr, TRUE) != 0) { + fprintf(stderr, _("Failed to create probe\n")); + return -1; + } + + if (!S_ISREG(dev->stat.st_mode) && blkid_probe_enable_topology(pr, TRUE) != 0) { + fprintf(stderr, _("Failed to create probe\n")); + return -1; + } + + ret = blkid_do_fullprobe(pr); + if (ret == -1) { + fprintf(stderr, _("Failed to probe device\n")); + return -1; + } + + if (ret == 1) + return 0; + + if (!blkid_probe_lookup_value(pr, "TYPE", &contents, NULL)) { + printf(_("It appears to contain an existing filesystem (%s)\n"), contents); + } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &contents, NULL)) { + printf(_("It appears to contain a partition table (%s).\n"), contents); + } + + if (!S_ISREG(dev->stat.st_mode)) { + blkid_topology tp = blkid_probe_get_topology(pr); + if (tp != NULL) { + dev->alignment_offset = blkid_topology_get_alignment_offset(tp); + dev->logical_sector_size = blkid_topology_get_logical_sector_size(tp); + dev->minimum_io_size = blkid_topology_get_minimum_io_size(tp); + dev->optimal_io_size = blkid_topology_get_optimal_io_size(tp); + dev->physical_sector_size = blkid_topology_get_physical_sector_size(tp); + dev->got_topol = (dev->logical_sector_size != 0 && + dev->physical_sector_size != 0); + } + } + + blkid_free_probe(pr); + return 0; +} + +static void open_dev(struct mkfs_dev *dev, int withprobe) +{ + int error; + + dev->fd = open(dev->path, O_RDWR|O_CLOEXEC|O_EXCL); + if (dev->fd < 0) { + perror(dev->path); + exit(1); + } + + /* Freshen up the cache */ + posix_fadvise(dev->fd, 0, 0, POSIX_FADV_DONTNEED); + /* Turn off readahead, we're just writing new blocks */ + posix_fadvise(dev->fd, 0, 0, POSIX_FADV_RANDOM); + + error = fstat(dev->fd, &dev->stat); + if (error < 0) { + perror(dev->path); + exit(1); + } + + if (S_ISREG(dev->stat.st_mode)) { + dev->size = dev->stat.st_size; + } else if (S_ISBLK(dev->stat.st_mode)) { + dev->size = lseek(dev->fd, 0, SEEK_END); + if (dev->size < 1) { + fprintf(stderr, _("Device '%s' is too small\n"), dev->path); + exit(1); + } + } else { + fprintf(stderr, _("'%s' is not a block device or regular file\n"), dev->path); + exit(1); + } + if (withprobe && (probe_contents(dev) != 0)) + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct gfs2_sbd sbd; + struct gfs2_sb sb; + struct mkfs_opts opts; + lgfs2_rgrps_t rgs; + uint64_t rgaddr; + int error; + unsigned bsize; + + setlocale(LC_ALL, ""); + textdomain("gfs2-utils"); + srandom(time(NULL) ^ getpid()); + + opts_init(&opts); + opts_get(argc, argv, &opts); + opts_check(&opts); + + open_dev(&opts.dev, !opts.got_topol); + bsize = choose_blocksize(&opts); + + if (S_ISREG(opts.dev.stat.st_mode)) { + opts.got_bsize = 1; /* Use default block size for regular files */ + } + + sbd_init(&sbd, &opts, bsize); + lgfs2_sb_init(&sb, bsize); + if (opts.debug) { + printf(_("File system options:\n")); + printf(" bsize = %u\n", sbd.bsize); + printf(" qcsize = %u\n", sbd.qcsize); + printf(" jsize = %u\n", sbd.jsize); + printf(" journals = %u\n", sbd.md.journals); + printf(" proto = %s\n", opts.lockproto); + printf(" table = %s\n", opts.locktable); + printf(" rgsize = %u\n", sbd.rgsize); + printf(" fssize = %"PRIu64"\n", opts.fssize); + printf(" sunit = %lu\n", opts.sunit); + printf(" swidth = %lu\n", opts.swidth); + } + rgs = rgs_init(&opts, &sbd); + warn_of_destruction(opts.dev.path); + + if (opts.confirm && !opts.override) + are_you_sure(); + + if (!S_ISREG(opts.dev.stat.st_mode) && opts.discard) { + if (!opts.quiet) { + printf("%s", _("Discarding device contents (may take a while on large devices): ")); + fflush(stdout); + } + discard_blocks(opts.dev.fd, opts.dev.size, opts.debug); + + if (!opts.quiet) + printf("%s", _("Done\n")); + } + rgaddr = lgfs2_rgrp_align_addr(rgs, LGFS2_SB_ADDR(&sbd) + 1); + error = place_journals(&sbd, rgs, &opts, &rgaddr); + if (error != 0) { + fprintf(stderr, _("Failed to create journals\n")); + exit(1); + } + error = place_rgrps(&sbd, rgs, &rgaddr, &opts); + if (error) { + fprintf(stderr, _("Failed to build resource groups\n")); + exit(1); + } + sbd.rgtree.osi_node = lgfs2_rgrps_root(rgs); // Temporary + + error = build_master(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "master", strerror(errno)); + exit(EXIT_FAILURE); + } + sb.sb_master_dir = sbd.master_dir->i_di.di_num; + + error = lgfs2_build_jindex(sbd.master_dir, mkfs_journals, opts.journals); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "jindex", strerror(errno)); + exit(EXIT_FAILURE); + } + free(mkfs_journals); + error = build_per_node(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "per_node", strerror(errno)); + exit(EXIT_FAILURE); + } + error = build_inum(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "inum", strerror(errno)); + exit(EXIT_FAILURE); + } + gfs2_lookupi(sbd.master_dir, "inum", 4, &sbd.md.inum); + error = build_statfs(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "statfs", strerror(errno)); + exit(EXIT_FAILURE); + } + gfs2_lookupi(sbd.master_dir, "statfs", 6, &sbd.md.statfs); + error = build_rindex(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "rindex", strerror(errno)); + exit(EXIT_FAILURE); + } + if (!opts.quiet) { + printf("%s", _("Creating quota file: ")); + fflush(stdout); + } + error = build_quota(&sbd); + if (error) { + fprintf(stderr, _("Error building '%s': %s\n"), "quota", strerror(errno)); + exit(EXIT_FAILURE); + } + if (!opts.quiet) + printf("%s", _("Done\n")); + + build_root(&sbd); + sb.sb_root_dir = sbd.md.rooti->i_di.di_num; + + strncpy(sb.sb_lockproto, opts.lockproto, GFS2_LOCKNAME_LEN); + strncpy(sb.sb_locktable, opts.locktable, GFS2_LOCKNAME_LEN); + sb.sb_lockproto[GFS2_LOCKNAME_LEN - 1] = '\0'; + sb.sb_locktable[GFS2_LOCKNAME_LEN - 1] = '\0'; + + do_init_inum(&sbd); + do_init_statfs(&sbd); + + inode_put(&sbd.md.rooti); + inode_put(&sbd.master_dir); + inode_put(&sbd.md.inum); + inode_put(&sbd.md.statfs); + + lgfs2_rgrps_free(&rgs); + + if (!opts.quiet) { + printf("%s", _("Writing superblock and syncing: ")); + fflush(stdout); + } + + error = lgfs2_sb_write(&sb, opts.dev.fd, sbd.bsize); + if (error) { + perror(_("Failed to write superblock\n")); + exit(EXIT_FAILURE); + } + + error = fsync(opts.dev.fd); + if (error){ + perror(opts.dev.path); + exit(EXIT_FAILURE); + } + posix_fadvise(opts.dev.fd, 0, 0, POSIX_FADV_DONTNEED); + error = close(opts.dev.fd); + if (error){ + perror(opts.dev.path); + exit(EXIT_FAILURE); + } + + if (!opts.quiet) { + printf("%s", _("Done\n")); + print_results(&sb, &opts, sbd.rgrps, sbd.fssize); + } + return 0; +} diff --git a/tests/mkfs.at b/tests/mkfs.at index 3e3fb82..4220567 100644 --- a/tests/mkfs.at +++ b/tests/mkfs.at @@ -112,6 +112,8 @@ AT_CLEANUP AT_SETUP([Device i/o limits handling]) AT_KEYWORDS(mkfs.gfs2 mkfs) AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:0:0:0:0 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:512:512:512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([gfs2_edit -p sb field sb_bsize $GFS_TGT | tr -d '\n' ], 0, [4096], [ignore]) AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=7168:512:0:33553920:512 $GFS_TGT], 0, [ignore], [ignore]) AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=7168:512:8192:33553920:512 $GFS_TGT], 0, [ignore], [Warning: device is not properly aligned. This may harm performance. ]) diff --git a/tests/mkfs.at.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size b/tests/mkfs.at.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size new file mode 100644 index 0000000..3e3fb82 --- /dev/null +++ b/tests/mkfs.at.bz1839219-mkfs_gfs2_Don_t_use_i_o_limits_hints_4K_for_block_size @@ -0,0 +1,169 @@ +AT_TESTED([mkfs.gfs2]) +AT_BANNER([mkfs.gfs2 tests]) + +AT_SETUP([Locking protocol validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p badprotocol $GFS_TGT], 255, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Resource group size validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 31 $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 2049 $GFS_TGT], 255, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Journal size validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -J 7 $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -J 1025 $GFS_TGT], 255, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Block count validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_TGT_REGEN +AT_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT $(($(gfs_max_blocks 512)+1))], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT $(($(gfs_max_blocks 4096)+1))], 255, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Quota change file size validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -c 0 $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -c 65 $GFS_TGT], 255, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Locking protocols]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_dlm -t foo:bar $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Valid block sizes 512-4096]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 1024 $GFS_TGT]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 2048 $GFS_TGT]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Max. blocks, min. block size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT $(gfs_max_blocks 512)]) +AT_CLEANUP + +AT_SETUP([Max. blocks, max. block size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT $(gfs_max_blocks 4096)]) +AT_CLEANUP + +AT_SETUP([Max. resource group size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 2048 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Min. resource group size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 32 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Max. resource group size, min. block size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 2048 -b 512 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Max. journal size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -J 1024 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Min. journal size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -J 8 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Max. quota change file size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -c 64 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Min. quota change file size]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -c 1 $GFS_TGT]) +AT_CLEANUP + +AT_SETUP([Lock table validation]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -t "" $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -t "123456789012345678901234567890123:12345678" $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -t "12345678901234567:1234567890123456789012345678901" $GFS_TGT], 255, [ignore], [ignore]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -t "12345678901234567890123456789012:123456789012345678901234567890" $GFS_TGT]) +AT_CHECK([$GFS_MKFS -p lock_dlm -t "" $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_dlm -t "quite_long_cluster_name_test_here:intec34p" $GFS_TGT], 255, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_dlm -t "financial_cluster:this_time_we_test_fs_naming_len" $GFS_TGT], 255, [ignore], [ignore]) +GFS_FSCK_CHECK([$GFS_MKFS -p lock_dlm -t "a_really_long_named_cluster_here:concurrently_lets_check_fs_len" $GFS_TGT]) +AT_CLEANUP + +# -o test_topology order: +# alignment_offset, +# logical_sector_size, +# minimum_io_size, +# optimal_io_size, +# physical_sector_size + +AT_SETUP([Device i/o limits handling]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:0:0:0:0 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=7168:512:0:33553920:512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=7168:512:8192:33553920:512 $GFS_TGT], 0, [ignore], [Warning: device is not properly aligned. This may harm performance. +]) +AT_CLEANUP + +AT_SETUP([Resource group alignment]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:65536:393216:512 $GFS_TGT], 0, [ignore], [ignore]) +# Check rgrp alignment to minimum_io_size: 65536 / 4096 == 16 +AT_CHECK([gfs2_edit -p rindex $GFS_TGT | grep ri_addr | awk '{print $2, $2 % 16; if ($2 % 16 != 0) { exit 1 }}'], 0, [ignore], [ignore]) +# rhbz#1698858 +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:131072:6291456:512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Values of rg_skip]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 2048 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 1024 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 219 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 32 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:65536:393216:512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgskipcheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Values of rg_data0, rg_data, rg_bitbytes]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 2048 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 1024 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 219 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -r 32 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:65536:393216:512 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([rgrifieldscheck.sh $GFS_TGT], 0, [ignore], [ignore]) +AT_CLEANUP + +AT_SETUP([Small filesystems]) +AT_KEYWORDS(mkfs.gfs2 mkfs) +GFS_TGT_SIZE(32M) +AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) +GFS_TGT_SIZE(64M) +AT_CHECK([$GFS_MKFS -p lock_nolock -j2 $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) +AT_CLEANUP