LCOV - code coverage report
Current view: top level - mkfs - main_jadd.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 0.0 % 369 0
Test Date: 2024-03-07 16:24:06 Functions: 0.0 % 17 0

            Line data    Source code
       1              : #include "clusterautoconfig.h"
       2              : 
       3              : #include <stdio.h>
       4              : #include <stdlib.h>
       5              : #include <string.h>
       6              : #include <stdint.h>
       7              : #include <inttypes.h>
       8              : #include <sys/types.h>
       9              : #include <dirent.h>
      10              : #include <sys/stat.h>
      11              : #include <sys/ioctl.h>
      12              : #include <sys/vfs.h>
      13              : #include <sys/mount.h>
      14              : #include <fcntl.h>
      15              : #include <unistd.h>
      16              : #include <time.h>
      17              : #include <errno.h>
      18              : #include <stdarg.h>
      19              : #include <libintl.h>
      20              : #include <locale.h>
      21              : #define _(String) gettext(String)
      22              : 
      23              : #include <linux/fiemap.h>
      24              : #include "libgfs2.h"
      25              : #include "gfs2_mkfs.h"
      26              : #include "metafs.h"
      27              : 
      28              : struct jadd_opts {
      29              :         char *path;
      30              :         char *new_inode;
      31              :         char *per_node;
      32              :         char *jindex;
      33              :         unsigned orig_journals;
      34              :         unsigned journals;
      35              :         unsigned jsize;
      36              :         unsigned qcsize;
      37              :         unsigned quiet:1;
      38              :         unsigned debug:1;
      39              : };
      40              : 
      41              : #define JA_FL_SET   0
      42              : #define JA_FL_CLEAR 1
      43            0 : static int set_flags(int fd, int op, uint32_t flags)
      44              : {
      45              :         uint32_t val;
      46              : 
      47            0 :         if (ioctl(fd, FS_IOC_GETFLAGS, &val)) {
      48            0 :                 perror("GETFLAGS");
      49            0 :                 return -1;
      50              :         }
      51              : 
      52            0 :         if (op == JA_FL_SET)
      53            0 :                 val |= flags;
      54            0 :         else if (op == JA_FL_CLEAR)
      55            0 :                 val &= ~flags;
      56              : 
      57            0 :         if (ioctl(fd, FS_IOC_SETFLAGS, &val)) {
      58            0 :                 perror("SETFLAGS");
      59            0 :                 return -1;
      60              :         }
      61            0 :         return 0;
      62              : }
      63              : 
      64            0 : static int rename2system(struct jadd_opts *opts, const char *new_dir, const char *new_name)
      65              : {
      66              :         char *newpath;
      67              :         int ret;
      68              : 
      69            0 :         if (asprintf(&newpath, "%s/%s", new_dir, new_name) < 0) {
      70            0 :                 perror(_("Failed to allocate new path"));
      71            0 :                 return -1;
      72              :         }
      73              : 
      74            0 :         ret = rename(opts->new_inode, newpath);
      75            0 :         free(newpath);
      76            0 :         return ret;
      77              : }
      78              : 
      79            0 : static int build_paths(const char *metafs_path, struct jadd_opts *opts)
      80              : {
      81            0 :         int i = 0;
      82              :         struct {
      83              :                 char **path;
      84              :                 const char *tail;
      85            0 :         } p[] = {
      86            0 :                 { &opts->new_inode, "new_inode" },
      87            0 :                 { &opts->per_node, "per_node" },
      88            0 :                 { &opts->jindex, "jindex" },
      89              :                 { NULL, NULL}
      90              :         };
      91              : 
      92            0 :         while (p[i].path != NULL) {
      93            0 :                 if (asprintf(p[i].path, "%s/%s", metafs_path, p[i].tail) < 0) {
      94            0 :                         while (i > 0)
      95            0 :                                 free(*p[--i].path);
      96            0 :                         return 1;
      97              :                 }
      98            0 :                 if (opts->debug)
      99            0 :                         printf("%d: %s\n", i, *p[i].path);
     100            0 :                 i++;
     101              :         }
     102            0 :         return 0;
     103              : }
     104              : 
     105              : /**
     106              :  * print_usage - print out usage information
     107              :  * @prog_name: The name of this program
     108              :  */
     109              : 
     110            0 : static void print_usage(const char *prog_name)
     111              : {
     112              :         int i;
     113              :         const char *option, *param, *desc;
     114            0 :         const char *options[] = {
     115              :                 /* Translators: This is a usage string printed with --help.
     116              :                    <size> and <number> here are the commandline parameters,
     117              :                    e.g. gfs2_jadd -j <number> /dev/sda */
     118            0 :                 "-c", "<size>",   _("Size of quota change file, in megabytes"),
     119            0 :                 "-D", NULL,       _("Enable debugging code"),
     120            0 :                 "-h", NULL,       _("Display this help, then exit"),
     121            0 :                 "-J", "<size>",   _("Size of journals, in megabytes"),
     122            0 :                 "-j", "<number>", _("Number of journals"),
     123            0 :                 "-q", NULL,       _("Don't print anything"),
     124            0 :                 "-V", NULL,       _("Display version information, then exit"),
     125              :                 NULL, NULL, NULL /* Must be kept at the end */
     126              :         };
     127              : 
     128            0 :         printf("%s\n", _("Usage:"));
     129            0 :         printf("%s [%s] <%s>\n\n", prog_name, _("options"), _("device"));
     130            0 :         printf(_("Adds journals to a GFS2 file system."));
     131            0 :         printf("\n\n%s\n", _("Options:"));
     132              : 
     133            0 :         for (i = 0; options[i] != NULL; i += 3) {
     134            0 :                 option = options[i];
     135            0 :                 param = options[i+1];
     136            0 :                 desc = options[i+2];
     137            0 :                 printf("%3s %-15s %s\n", option, param ? param : "", desc);
     138              :         }
     139            0 : }
     140              : 
     141              : /**
     142              :  * Decode command line arguments and fill in the struct lgfs2_sbd
     143              :  * @argc:
     144              :  * @argv:
     145              :  * @sdp: the decoded command line arguments
     146              :  */
     147            0 : static int decode_arguments(int argc, char *argv[], struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     148              : {
     149            0 :         int cont = 1;
     150              :         int optchar;
     151              : 
     152            0 :         while (cont) {
     153            0 :                 optchar = getopt(argc, argv, "c:DhJ:j:qu:V");
     154              : 
     155            0 :                 switch (optchar) {
     156            0 :                 case 'c':
     157            0 :                         opts->qcsize = atoi(optarg);
     158            0 :                         break;
     159            0 :                 case 'D':
     160            0 :                         opts->debug = 1;
     161            0 :                         break;
     162            0 :                 case 'h':
     163            0 :                         print_usage(argv[0]);
     164            0 :                         return 1;
     165            0 :                 case 'J':
     166            0 :                         opts->jsize = atoi(optarg);
     167            0 :                         break;
     168            0 :                 case 'j':
     169            0 :                         opts->journals = atoi(optarg);
     170            0 :                         break;
     171            0 :                 case 'q':
     172            0 :                         opts->quiet = 1;
     173            0 :                         break;
     174            0 :                 case 'V':
     175            0 :                         printf("gfs2_jadd %s (built %s %s)\n", VERSION,
     176              :                                __DATE__, __TIME__);
     177            0 :                         printf(REDHAT_COPYRIGHT "\n");
     178            0 :                         return 1;
     179            0 :                 case ':':
     180              :                 case '?':
     181            0 :                         fprintf(stderr, _("Please use '-h' for help.\n"));
     182            0 :                         return -1;
     183            0 :                 case EOF:
     184            0 :                         cont = 0;
     185            0 :                         break;
     186            0 :                 default:
     187            0 :                         fprintf(stderr, _("Invalid option: %c\n"), optchar);
     188            0 :                         return -1;
     189              :                 };
     190              :         }
     191              : 
     192            0 :         if (optind < argc) {
     193            0 :                 opts->path = argv[optind];
     194            0 :                 optind++;
     195              :         } else {
     196            0 :                 fprintf(stderr, _("no path specified (try -h for help)\n"));
     197            0 :                 return -1;
     198              :         }
     199            0 :         if (optind < argc) {
     200            0 :                 fprintf(stderr, _("Unrecognized argument: %s\n"), argv[optind]);
     201            0 :                 return -1;
     202              :         }
     203            0 :         if (opts->debug) {
     204            0 :                 printf( _("Command line arguments:\n"));
     205            0 :                 printf("  qcsize = %u\n", opts->qcsize);
     206            0 :                 printf("  jsize = %u\n", opts->jsize);
     207            0 :                 printf("  journals = %u\n", sdp->md.journals);
     208            0 :                 printf("  quiet = %u\n", opts->quiet);
     209            0 :                 printf("  path = %s\n", opts->path);
     210              :         }
     211            0 :         return 0;
     212              : }
     213              : 
     214            0 : static int verify_arguments(struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     215              : {
     216            0 :         if (!opts->journals) {
     217            0 :                 fprintf(stderr, _("no journals specified\n"));
     218            0 :                 return -1;
     219              :         }
     220            0 :         if (opts->jsize < 32 || opts->jsize > 1024) {
     221            0 :                 fprintf(stderr, _("bad journal size\n"));
     222            0 :                 return -1;
     223              :         }
     224            0 :         if (!opts->qcsize || opts->qcsize > 64) {
     225            0 :                 fprintf(stderr, _("bad quota change size\n"));
     226            0 :                 return -1;
     227              :         }
     228            0 :         return 0;
     229              : }
     230              : 
     231            0 : static void print_results(struct jadd_opts *opts)
     232              : {
     233            0 :         if (opts->debug)
     234            0 :                 printf("\n");
     235            0 :         else if (opts->quiet)
     236            0 :                 return;
     237              : 
     238            0 :         printf( _("Filesystem: %s\n"), opts->path);
     239            0 :         printf( _("Old journals: %u\n"), opts->orig_journals);
     240            0 :         printf( _("New journals: %u\n"), opts->journals);
     241              : }
     242              : 
     243            0 : static int create_new_inode(struct jadd_opts *opts, uint64_t *addr)
     244              : {
     245            0 :         char *name = opts->new_inode;
     246              :         int fd;
     247              : 
     248              :         for (;;) {
     249            0 :                 fd = open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600);
     250            0 :                 if (fd >= 0)
     251            0 :                         break;
     252            0 :                 if (errno == EEXIST) {
     253            0 :                         if (unlink(name)) {
     254            0 :                                 perror("unlink");
     255            0 :                                 return -1;
     256              :                         }
     257            0 :                         continue;
     258              :                 }
     259            0 :                 perror("create");
     260            0 :                 return -1;
     261              :         }
     262              : 
     263            0 :         if (addr != NULL) {
     264              :                 struct stat st;
     265              : 
     266            0 :                 if (fstat(fd, &st) == -1) {
     267            0 :                         perror("fstat");
     268            0 :                         close(fd);
     269            0 :                         return -1;
     270              :                 }
     271            0 :                 *addr = st.st_ino;
     272              :         }
     273              : 
     274            0 :         return fd;
     275              : }
     276              : 
     277            0 : static int add_ir(struct jadd_opts *opts)
     278              : {
     279            0 :         int fd, error = 0;
     280              :         char new_name[256];
     281              :         struct gfs2_inum_range ir;
     282              : 
     283            0 :         if ((fd = create_new_inode(opts, NULL)) < 0)
     284            0 :                 return fd;
     285              : 
     286            0 :         if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL)))
     287            0 :                 goto close_fd;
     288              : 
     289            0 :         memset(&ir, 0, sizeof(struct gfs2_inum_range));
     290            0 :         if (write(fd, (void*)&ir, sizeof(struct gfs2_inum_range)) !=
     291              :             sizeof(struct gfs2_inum_range)) {
     292            0 :                 perror("add_ir write");
     293            0 :                 error = -1;
     294            0 :                 goto close_fd;
     295              :         }
     296              : 
     297            0 :         if ((error = fsync(fd))) {
     298            0 :                 perror("add_ir fsync");
     299            0 :                 goto close_fd;
     300              :         }
     301              : 
     302              : 
     303            0 :         sprintf(new_name, "inum_range%u", opts->journals);
     304            0 :         error = rename2system(opts, opts->per_node, new_name);
     305            0 :         if (error < 0 && errno != EEXIST) {
     306            0 :                 perror("add_ir rename2system");
     307            0 :                 goto close_fd;
     308              :         }
     309            0 : close_fd:
     310            0 :         return close(fd) || error;
     311              : }
     312              : 
     313            0 : static int add_sc(struct jadd_opts *opts)
     314              : {
     315            0 :         int fd, error = 0;
     316              :         char new_name[256];
     317              :         struct gfs2_statfs_change sc;
     318              : 
     319            0 :         if ((fd = create_new_inode(opts, NULL)) < 0)
     320            0 :                 return fd;
     321              : 
     322            0 :         if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL)))
     323            0 :                 goto close_fd;
     324              : 
     325            0 :         memset(&sc, 0, sizeof(struct gfs2_statfs_change));
     326            0 :         if (write(fd, (void*)&sc, sizeof(struct gfs2_statfs_change)) !=
     327              :             sizeof(struct gfs2_statfs_change)) {
     328            0 :                 perror("add_sc write");
     329            0 :                 error = -1;
     330            0 :                 goto close_fd;
     331              :         }
     332              : 
     333            0 :         if ((error = fsync(fd))) {
     334            0 :                 perror("add_sc fsync");
     335            0 :                 goto close_fd;
     336              :         }
     337              : 
     338            0 :         sprintf(new_name, "statfs_change%u", opts->journals);
     339            0 :         error = rename2system(opts, opts->per_node, new_name);
     340            0 :         if (error < 0 && errno != EEXIST){
     341            0 :                 perror("add_sc rename2system");
     342            0 :                 goto close_fd;
     343              :         }
     344            0 : close_fd:
     345            0 :         return close(fd) || error;
     346              : }
     347              : 
     348            0 : static int add_qc(struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     349              : {
     350            0 :         int fd, error = 0;
     351              :         char new_name[256], *buf;
     352            0 :         unsigned int blocks =
     353            0 :                 opts->qcsize << (20 - sdp->sd_bsize_shift);
     354              :         unsigned int x;
     355              :         struct gfs2_meta_header mh;
     356              : 
     357            0 :         buf = calloc(1, sdp->sd_bsize);
     358            0 :         if (buf == NULL)
     359            0 :                 return -1;
     360              : 
     361            0 :         if ((fd = create_new_inode(opts, NULL)) < 0) {
     362            0 :                 free(buf);
     363            0 :                 return fd;
     364              :         }
     365            0 :         if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL)))
     366            0 :                 goto close_fd;
     367              : 
     368            0 :         memset(buf, 0, sdp->sd_bsize);
     369            0 :         for (x=0; x<blocks; x++) {
     370            0 :                 if (write(fd, buf, sdp->sd_bsize) != sdp->sd_bsize) {
     371            0 :                         perror("add_qc write");
     372            0 :                         error = -1;
     373            0 :                         goto close_fd;
     374              :                 }
     375              :         }
     376              : 
     377            0 :         if ((error = lseek(fd, 0, SEEK_SET)) < 0) {
     378            0 :                 perror("add_qc lseek");
     379            0 :                 goto close_fd;
     380              :         }
     381              : 
     382            0 :         memset(&mh, 0, sizeof(struct gfs2_meta_header));
     383            0 :         mh.mh_magic = cpu_to_be32(GFS2_MAGIC);
     384            0 :         mh.mh_type = cpu_to_be32(GFS2_METATYPE_QC);
     385            0 :         mh.mh_format = cpu_to_be32(GFS2_FORMAT_QC);
     386            0 :         memcpy(buf, &mh, sizeof(mh));
     387              : 
     388            0 :         for (x=0; x<blocks; x++) {
     389            0 :                 if (write(fd, buf, sdp->sd_bsize) != sdp->sd_bsize) {
     390            0 :                         perror("add_qc write");
     391            0 :                         error = 1;
     392            0 :                         goto close_fd;
     393              :                 }
     394            0 :                 if ((error = fsync(fd))) {
     395            0 :                         perror("add_qc fsync");
     396            0 :                         goto close_fd;
     397              :                 }
     398              :         }
     399              : 
     400            0 :         sprintf(new_name, "quota_change%u", opts->journals);
     401            0 :         error = rename2system(opts, opts->per_node, new_name);
     402            0 :         if (error < 0 && errno != EEXIST){
     403            0 :                 perror("add_qc rename2system");
     404            0 :                 goto close_fd;
     405              :         }
     406            0 : close_fd:
     407            0 :         free(buf);
     408            0 :         return close(fd) || error;
     409              : }
     410              : 
     411            0 : static int gather_info(struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     412              : {
     413              :         struct statfs statbuf;
     414              : 
     415            0 :         if (statfs(opts->path, &statbuf) < 0) {
     416            0 :                 perror(opts->path);
     417            0 :                 return -1;
     418              :         }
     419              : 
     420            0 :         sdp->sd_bsize = statbuf.f_bsize;
     421            0 :         sdp->blks_total = statbuf.f_blocks;
     422            0 :         sdp->blks_alloced = sdp->blks_total - statbuf.f_bfree;
     423              : 
     424            0 :         return 0;
     425              : }
     426              : 
     427            0 : static int find_current_journals(struct jadd_opts *opts)
     428              : {
     429              :         struct dirent *dp;
     430              :         DIR *dirp;
     431            0 :         unsigned existing_journals = 0;
     432            0 :         int ret = 0;
     433              : 
     434            0 :         dirp = opendir(opts->jindex);
     435            0 :         if (!dirp) {
     436            0 :                 perror("jindex");
     437            0 :                 ret = -1;
     438            0 :                 goto out;
     439              :         }
     440            0 :         while (dirp) {
     441            0 :                 if ((dp = readdir(dirp)) != NULL) {
     442            0 :                         if (strncmp(dp->d_name, "journal", 7) == 0)
     443            0 :                                 existing_journals++;
     444              :                 } else
     445            0 :                         goto close_fd;
     446              :         }
     447            0 : close_fd:
     448            0 :         if ((ret = closedir(dirp)))
     449            0 :                 goto out;
     450              : 
     451            0 :         if (existing_journals == 0) {
     452            0 :                 errno = EINVAL;
     453            0 :                 perror("No journals found. Did you run mkfs.gfs2 correctly?\n");
     454            0 :                 ret = -1;
     455            0 :                 goto out;
     456              :         }
     457              : 
     458            0 :         opts->orig_journals = existing_journals;
     459            0 : out:
     460            0 :         return ret;
     461              : }
     462              : 
     463            0 : static uint64_t find_block_address(int fd, off_t offset, unsigned bsize)
     464              : {
     465              :         struct {
     466              :                 struct fiemap fm;
     467              :                 struct fiemap_extent fe;
     468            0 :         } fme = {0};
     469              :         int ret;
     470              : 
     471            0 :         fme.fm.fm_start = offset;
     472            0 :         fme.fm.fm_length = 1;
     473            0 :         fme.fm.fm_flags = FIEMAP_FLAG_SYNC;
     474            0 :         fme.fm.fm_extent_count = 1;
     475              : 
     476            0 :         ret = ioctl(fd, FS_IOC_FIEMAP, &fme.fm);
     477            0 :         if (ret != 0 || fme.fm.fm_mapped_extents != 1) {
     478            0 :                 fprintf(stderr, "Failed to find log header block address\n");
     479            0 :                 return 0;
     480              :         }
     481            0 :         return fme.fe.fe_physical / bsize;
     482              : }
     483              : 
     484            0 : static int alloc_new_journal(int fd, unsigned bytes)
     485              : {
     486              : #define ALLOC_BUF_SIZE (4 << 20)
     487            0 :         unsigned left = bytes;
     488              :         int error;
     489              :         char *buf;
     490              : 
     491            0 :         error = fallocate(fd, 0, 0, bytes);
     492            0 :         if (error == 0)
     493            0 :                return 0;
     494            0 :         if (errno != EOPNOTSUPP)
     495            0 :                 goto out_errno;
     496              : 
     497              :         /* No fallocate support, fall back to writes */
     498            0 :         buf = calloc(1, ALLOC_BUF_SIZE);
     499            0 :         if (buf == NULL)
     500            0 :                 goto out_errno;
     501              : 
     502            0 :         while (left > 0) {
     503            0 :                 unsigned sz = ALLOC_BUF_SIZE;
     504              : 
     505            0 :                 if (left < ALLOC_BUF_SIZE)
     506            0 :                         sz = left;
     507              : 
     508            0 :                 if (pwrite(fd, buf, sz, bytes - left) != sz) {
     509            0 :                         free(buf);
     510            0 :                         goto out_errno;
     511              :                 }
     512            0 :                 left -= sz;
     513              :         }
     514            0 :         free(buf);
     515            0 :         return 0;
     516            0 : out_errno:
     517            0 :         perror("Failed to allocate space for new journal");
     518            0 :         return -1;
     519              : }
     520              : 
     521            0 : static int add_j(struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     522              : {
     523            0 :         int fd, error = 0;
     524              :         char new_name[256], *buf;
     525            0 :         uint32_t x, blocks = opts->jsize << (20 - sdp->sd_bsize_shift);
     526              :         struct gfs2_log_header *lh;
     527              :         /* Not a security sensitive use of random() */
     528              :         /* coverity[dont_call:SUPPRESS] */
     529            0 :         uint64_t seq = blocks * (random() / (RAND_MAX + 1.0));
     530            0 :         uint64_t addr = 0;
     531            0 :         off_t off = 0;
     532              : 
     533            0 :         buf = calloc(1, sdp->sd_bsize);
     534            0 :         if (buf == NULL)
     535            0 :                 return -1;
     536              : 
     537            0 :         if ((fd = create_new_inode(opts, &addr)) < 0) {
     538            0 :                 free(buf);
     539            0 :                 return fd;
     540              :         }
     541            0 :         if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL)))
     542            0 :                 goto close_fd;
     543              : 
     544            0 :         error = alloc_new_journal(fd, opts->jsize << 20);
     545            0 :         if (error != 0)
     546            0 :                 goto close_fd;
     547              : 
     548            0 :         error = fsync(fd);
     549            0 :         if (error != 0) {
     550            0 :                 perror("Failed to sync journal metadata");
     551            0 :                 goto close_fd;
     552              :         }
     553            0 :         if ((error = lseek(fd, 0, SEEK_SET)) < 0) {
     554            0 :                 perror("add_j lseek");
     555            0 :                 goto close_fd;
     556              :         }
     557              : 
     558            0 :         lh = (void *)buf;
     559            0 :         lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
     560            0 :         lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
     561            0 :         lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
     562            0 :         lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE);
     563            0 :         lh->lh_jinode = cpu_to_be64(addr);
     564              : 
     565            0 :         for (x=0; x<blocks; x++) {
     566              :                 uint32_t hash;
     567            0 :                 uint64_t blk_addr = 0;
     568            0 :                 lh->lh_sequence = cpu_to_be64(seq);
     569            0 :                 lh->lh_blkno = cpu_to_be32(x);
     570            0 :                 hash = lgfs2_log_header_hash(buf);
     571            0 :                 lh->lh_hash = cpu_to_be32(hash);
     572            0 :                 if (!(blk_addr = find_block_address(fd, off, sdp->sd_bsize))) {
     573            0 :                         error = -1;
     574            0 :                         goto close_fd;
     575              :                 }
     576            0 :                 lh->lh_addr = cpu_to_be64(blk_addr);
     577            0 :                 hash = lgfs2_log_header_crc(buf, sdp->sd_bsize);
     578            0 :                 lh->lh_crc = cpu_to_be32(hash);
     579            0 :                 if (write(fd, buf, sdp->sd_bsize) != sdp->sd_bsize) {
     580            0 :                         perror("add_j write");
     581            0 :                         error = -1;
     582            0 :                         goto close_fd;
     583              :                 }
     584            0 :                 lh->lh_crc = 0;
     585            0 :                 lh->lh_hash = 0;
     586              : 
     587            0 :                 if (++seq == blocks)
     588            0 :                         seq = 0;
     589            0 :                 off += sdp->sd_bsize;
     590              : 
     591              :         }
     592            0 :         error = fsync(fd);
     593            0 :         if (error != 0) {
     594            0 :                 perror("Failed to sync journal metadata");
     595            0 :                 goto close_fd;
     596              :         }
     597            0 :         sprintf(new_name, "journal%u", opts->journals);
     598            0 :         error = rename2system(opts, opts->jindex, new_name);
     599            0 :         if (error < 0 && errno != EEXIST){
     600            0 :                 perror("add_j rename2system");
     601            0 :                 goto close_fd;
     602              :         }
     603            0 : close_fd:
     604            0 :         free(buf);
     605            0 :         return close(fd) || error;
     606              : }
     607              : 
     608            0 : static int check_fit(struct lgfs2_sbd *sdp, struct jadd_opts *opts)
     609              : {
     610              :         /* Compute how much space we'll need for the new journals
     611              :          * Number of blocks needed per added journal:
     612              :          * 1 block for the ir inode
     613              :          * 1 block for the sc inode
     614              :          * for sizes of the qc and journal inodes, use lgfs2_space_for_data()
     615              :          * to calculate.
     616              :          */
     617              :         uint64_t blks_per_j, total_blks;
     618              : 
     619            0 :         blks_per_j = 1 + 1 +
     620            0 :                 lgfs2_space_for_data(sdp, sdp->sd_bsize, opts->qcsize << 20) +
     621            0 :                 lgfs2_space_for_data(sdp, sdp->sd_bsize, opts->jsize << 20);
     622            0 :         total_blks = opts->journals * blks_per_j;
     623              : 
     624            0 :         if (total_blks > (sdp->blks_total - sdp->blks_alloced)) {
     625            0 :                 printf( _("\nInsufficient space on the device to add %u %uMB "
     626              :                           "journals (%uMB QC size)\n\n"),
     627              :                         opts->journals, opts->jsize, opts->qcsize);
     628            0 :                 printf( _("Required space  : %*"PRIu64" blocks (%"PRIu64" blocks per "
     629              :                           "journal)\n"), 10, total_blks, blks_per_j);
     630            0 :                 printf( _("Available space : %*"PRIu64" blocks\n\n"), 10,
     631            0 :                         sdp->blks_total - sdp->blks_alloced);
     632            0 :                 errno = ENOSPC;
     633            0 :                 return -1;
     634              :         }
     635            0 :         return 0;
     636              : }
     637              : 
     638              : #ifndef UNITTESTS
     639              : int main(int argc, char *argv[])
     640              : {
     641              :         struct jadd_opts opts = {0};
     642              :         struct lgfs2_sbd sbd, *sdp = &sbd;
     643              :         struct metafs mfs = {0};
     644              :         struct mntent *mnt;
     645              :         unsigned int total, ret = 0;
     646              : 
     647              :         setlocale(LC_ALL, "");
     648              :         textdomain("gfs2-utils");
     649              :         srandom(time(NULL) ^ getpid());
     650              : 
     651              :         memset(sdp, 0, sizeof(struct lgfs2_sbd));
     652              :         opts.jsize = LGFS2_DEFAULT_JSIZE;
     653              :         opts.qcsize = LGFS2_DEFAULT_QCSIZE;
     654              :         opts.journals = 1;
     655              : 
     656              :         ret = decode_arguments(argc, argv, sdp, &opts);
     657              :         if (ret == 1)
     658              :                 exit(0);
     659              :         if (ret != 0)
     660              :                 exit(1);
     661              :         if (verify_arguments(sdp, &opts) != 0)
     662              :                 exit(1);
     663              : 
     664              :         sbd.path_fd = lgfs2_open_mnt_dir(opts.path, O_RDONLY|O_CLOEXEC, &mnt);
     665              :         if (sbd.path_fd < 0) {
     666              :                 fprintf(stderr, "Error looking up mount '%s': %s\n",
     667              :                         opts.path, strerror(errno));
     668              :                 ret = -1;
     669              :                 goto out;
     670              :         }
     671              :         if (mnt == NULL) {
     672              :                 fprintf(stderr, "%s: not a mounted gfs2 file system\n", opts.path);
     673              :                 ret = -1;
     674              :                 goto close_sb;
     675              :         }
     676              : 
     677              :         if ((ret = gather_info(sdp, &opts)))
     678              :                 goto close_sb;
     679              : 
     680              :         mfs.context = copy_context_opt(mnt);
     681              :         if ((ret = mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug))) {
     682              :                 perror("GFS2 metafs");
     683              :                 goto close_sb;
     684              :         }
     685              : 
     686              :         if ((ret = build_paths(mfs.path, &opts))) {
     687              :                 perror(_("Failed to build paths"));
     688              :                 goto umount_meta;
     689              :         }
     690              : 
     691              :         if ((ret = lgfs2_compute_constants(sdp))) {
     692              :                 perror(_("Failed to compute file system constants"));
     693              :                 goto free_paths;
     694              :         }
     695              : 
     696              :         if ((ret = find_current_journals(&opts)))
     697              :                 goto free_paths;
     698              : 
     699              :         if ((ret = check_fit(sdp, &opts))) {
     700              :                 perror(_("Failed to add journals"));
     701              :                 goto free_paths;
     702              :         }
     703              : 
     704              :         total = opts.orig_journals + opts.journals;
     705              :         for (opts.journals = opts.orig_journals;
     706              :              opts.journals < total;
     707              :              opts.journals++) {
     708              :                 if (metafs_interrupted) {
     709              :                         errno = 130;
     710              :                         goto free_paths;
     711              :                 }
     712              :                 if ((ret = add_ir(&opts)))
     713              :                         goto free_paths;
     714              :                 if ((ret = add_sc(&opts)))
     715              :                         goto free_paths;
     716              :                 if ((ret = add_qc(sdp, &opts)))
     717              :                         goto free_paths;
     718              :                 if ((ret = add_j(sdp, &opts)))
     719              :                         goto free_paths;
     720              :         }
     721              : 
     722              : free_paths:
     723              :         free(opts.new_inode);
     724              :         free(opts.per_node);
     725              :         free(opts.jindex);
     726              : umount_meta:
     727              :         sync();
     728              :         cleanup_metafs(&mfs);
     729              : close_sb:
     730              :         close(sdp->path_fd);
     731              : out:
     732              :         if (!ret)
     733              :                 print_results(&opts);
     734              : 
     735              :         return ret;
     736              : }
     737              : #endif /* UNITTESTS */
        

Generated by: LCOV version 2.0-1