LCOV - code coverage report
Current view: top level - mkfs - main_jadd.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 0 369 0.0 %
Date: 2023-10-25 12:04:14 Functions: 0 17 0.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 1.14