LCOV - code coverage report
Current view: top level - mkfs - main_grow.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 0 179 0.0 %
Date: 2023-09-27 13:48:55 Functions: 0 10 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/mount.h>
      13             : #include <fcntl.h>
      14             : #include <unistd.h>
      15             : #include <time.h>
      16             : #include <errno.h>
      17             : #include <stdarg.h>
      18             : #include <blkid.h>
      19             : #include <libintl.h>
      20             : #include <locale.h>
      21             : #define _(String) gettext(String)
      22             : 
      23             : #include <logging.h>
      24             : #include "libgfs2.h"
      25             : #include "gfs2_mkfs.h"
      26             : #include "metafs.h"
      27             : 
      28             : #define BUF_SIZE 4096
      29             : #define MB (1024 * 1024)
      30             : 
      31             : static uint64_t override_device_size = 0;
      32             : static int test = 0;
      33             : static uint64_t fssize = 0, fsgrowth;
      34             : int print_level = MSG_NOTICE;
      35             : 
      36             : extern int create_new_inode(struct lgfs2_sbd *sdp);
      37             : extern int rename2system(struct lgfs2_sbd *sdp, char *new_dir, char *new_name);
      38             : 
      39             : #ifndef FALLOC_FL_KEEP_SIZE
      40             : #define FALLOC_FL_KEEP_SIZE 0x01
      41             : #endif
      42             : #ifndef BLKDISCARD
      43             : #define BLKDISCARD      _IO(0x12,119)
      44             : #endif
      45             : 
      46           0 : static int discard_blocks(int fd, uint64_t start, uint64_t len)
      47             : {
      48           0 :         uint64_t range[2] = { start, len };
      49             : 
      50           0 :         if (ioctl(fd, BLKDISCARD, &range) < 0)
      51           0 :                 return errno;
      52           0 :         return 0;
      53             : }
      54             : 
      55             : /**
      56             :  * usage - Print out the usage message
      57             :  *
      58             :  * This function does not include documentation for the -D option
      59             :  * since normal users have no use for it at all. The -D option is
      60             :  * only for developers. It intended use is in combination with the
      61             :  * -T flag to find out what the result would be of trying different
      62             :  * device sizes without actually having to try them manually.
      63             :  */
      64             : 
      65           0 : static void usage(void)
      66             : {
      67             :         int i;
      68             :         const char *option, *param, *desc;
      69           0 :         const char *options[] = {
      70           0 :                 "-h", NULL, _("Display this usage information"),
      71           0 :                 "-q", NULL, _("Quiet, reduce verbosity"),
      72           0 :                 "-T", NULL, _("Do everything except update file system"),
      73           0 :                 "-V", NULL, _("Display version information"),
      74           0 :                 "-v", NULL, _("Increase verbosity"),
      75             :                 NULL, NULL, NULL /* Must be kept at the end */
      76             :         };
      77             : 
      78           0 :         printf("%s\n", _("Usage:"));
      79           0 :         printf("    gfs2_grow [%s] <%s>\n\n", _("options"), _("device"));
      80           0 :         printf(_("Expands a GFS2 file system after the device containing the file system has been expanded"));
      81           0 :         printf("\n\n%s\n", _("Options:"));
      82             : 
      83           0 :         for (i = 0; options[i] != NULL; i += 3) {
      84           0 :                 option = options[i];
      85           0 :                 param = options[i+1];
      86           0 :                 desc = options[i+2];
      87           0 :                 printf("%3s %-15s %s\n", option, param ? param : "", desc);
      88             :         }
      89           0 : }
      90             : 
      91           0 : static void decode_arguments(int argc, char *argv[], struct lgfs2_sbd *sdp)
      92             : {
      93             :         int opt;
      94             : 
      95           0 :         while ((opt = getopt(argc, argv, "VD:hqTv?")) != EOF) {
      96           0 :                 switch (opt) {
      97           0 :                 case 'D':       /* This option is for testing only */
      98           0 :                         override_device_size = atoi(optarg);
      99           0 :                         override_device_size <<= 20;
     100           0 :                         break;
     101           0 :                 case 'V':
     102           0 :                         printf(_("%s %s (built %s %s)\n"), argv[0],
     103             :                                VERSION, __DATE__, __TIME__);
     104           0 :                         printf(REDHAT_COPYRIGHT "\n");
     105           0 :                         exit(0);
     106           0 :                 case 'h':
     107           0 :                         usage();
     108           0 :                         exit(0);
     109           0 :                 case 'q':
     110           0 :                         decrease_verbosity();
     111           0 :                         break;
     112           0 :                 case 'T':
     113           0 :                         printf( _("(Test mode - file system will not "
     114             :                                "be changed)\n"));
     115           0 :                         test = 1;
     116           0 :                         break;
     117           0 :                 case 'v':
     118           0 :                         increase_verbosity();
     119           0 :                         break;
     120           0 :                 case ':':
     121             :                 case '?':
     122             :                         /* Unknown flag */
     123           0 :                         fprintf(stderr, _("Please use '-h' for help.\n"));
     124           0 :                         exit(EXIT_FAILURE);
     125           0 :                 default:
     126           0 :                         fprintf(stderr, _("Invalid option '%c'\n"), opt);
     127           0 :                         exit(EXIT_FAILURE);
     128             :                         break;
     129             :                 }
     130             :         }
     131             : 
     132           0 :         if (optind == argc) {
     133           0 :                 usage();
     134           0 :                 exit(EXIT_FAILURE);
     135             :         }
     136           0 : }
     137             : 
     138           0 : static lgfs2_rgrps_t rgrps_init(struct lgfs2_sbd *sdp)
     139             : {
     140             :         int ret;
     141             :         int error;
     142           0 :         uint64_t al_base = 0;
     143           0 :         uint64_t al_off = 0;
     144             :         struct stat st;
     145           0 :         blkid_probe pr = blkid_new_probe();
     146           0 :         if (pr == NULL || blkid_probe_set_device(pr, sdp->device_fd, 0, 0) != 0
     147           0 :                        || blkid_probe_enable_superblocks(pr, 1) != 0
     148           0 :                        || blkid_probe_enable_partitions(pr, 1) != 0) {
     149           0 :                 fprintf(stderr, _("Failed to create probe\n"));
     150           0 :                 return NULL;
     151             :         }
     152             : 
     153           0 :         error = fstat(sdp->device_fd, &st);
     154           0 :         if (error < 0) {
     155           0 :                 fprintf(stderr, _("fstat failed\n"));
     156           0 :                 return NULL;
     157             :         }
     158             : 
     159           0 :         if (!S_ISREG(st.st_mode) && blkid_probe_enable_topology(pr, 1) != 0) {
     160           0 :                 fprintf(stderr, _("Failed to create probe\n"));
     161           0 :                 return NULL;
     162             :         }
     163             : 
     164           0 :         ret = blkid_do_fullprobe(pr);
     165           0 :         if (ret == 0 && !S_ISREG(st.st_mode)) {
     166           0 :                 blkid_topology tp = blkid_probe_get_topology(pr);
     167           0 :                 if (tp != NULL) {
     168           0 :                         unsigned long min_io_sz = blkid_topology_get_minimum_io_size(tp);
     169           0 :                         unsigned long opt_io_sz = blkid_topology_get_optimal_io_size(tp);
     170           0 :                         unsigned long phy_sector_sz = blkid_topology_get_physical_sector_size(tp);
     171             :                         /* If optimal_io_size is not a multiple of minimum_io_size then
     172             :                            the values are not reliable swidth and sunit values, so don't
     173             :                            attempt rgrp alignment */
     174           0 :                         if ((min_io_sz > phy_sector_sz) &&
     175           0 :                             (opt_io_sz > phy_sector_sz) &&
     176           0 :                             (opt_io_sz % min_io_sz == 0)) {
     177           0 :                                         al_base = opt_io_sz / sdp->sd_bsize;
     178           0 :                                         al_off = min_io_sz / sdp->sd_bsize;
     179             :                         }
     180             : 
     181             :                 }
     182             :         }
     183             : 
     184           0 :         blkid_free_probe(pr);
     185           0 :         return lgfs2_rgrps_init(sdp, al_base, al_off);
     186             : }
     187             : 
     188             : /**
     189             :  * Calculate the size of the filesystem
     190             :  * Reads the lists of resource groups in order to work out where the last block
     191             :  * of the filesystem is located.
     192             :  * Returns: The calculated size
     193             :  */
     194           0 : static uint64_t filesystem_size(lgfs2_rgrps_t rgs)
     195             : {
     196           0 :         lgfs2_rgrp_t rg = lgfs2_rgrp_last(rgs);
     197             :         struct gfs2_rindex ri;
     198             : 
     199           0 :         lgfs2_rindex_out(rg, &ri);
     200           0 :         return be64_to_cpu(ri.ri_data0) + be32_to_cpu(ri.ri_data);
     201             : }
     202             : 
     203             : /**
     204             :  * Write the new rg information to disk.
     205             :  */
     206           0 : static unsigned initialize_new_portion(struct lgfs2_sbd *sdp, lgfs2_rgrps_t rgs)
     207             : {
     208           0 :         unsigned rgcount = 0;
     209           0 :         uint64_t rgaddr = fssize;
     210             : 
     211           0 :         discard_blocks(sdp->device_fd, rgaddr * sdp->sd_bsize, fsgrowth * sdp->sd_bsize);
     212             :         /* Build the remaining resource groups */
     213           0 :         while (1) {
     214           0 :                 int err = 0;
     215             :                 lgfs2_rgrp_t rg;
     216             :                 struct gfs2_rindex ri;
     217             :                 uint64_t nextaddr;
     218             : 
     219           0 :                 nextaddr = lgfs2_rindex_entry_new(rgs, &ri, rgaddr, 0);
     220           0 :                 if (nextaddr == 0)
     221           0 :                         break;
     222           0 :                 rg = lgfs2_rgrps_append(rgs, &ri, nextaddr - rgaddr);
     223           0 :                 if (rg == NULL) {
     224           0 :                         perror(_("Failed to create resource group"));
     225           0 :                         return 0;
     226             :                 }
     227           0 :                 rgaddr = nextaddr;
     228           0 :                 if (metafs_interrupted)
     229           0 :                         return 0;
     230           0 :                 if (!test)
     231           0 :                         err = lgfs2_rgrp_write(sdp->device_fd, rg);
     232           0 :                 if (err != 0) {
     233           0 :                         perror(_("Failed to write resource group"));
     234           0 :                         return 0;
     235             :                 }
     236           0 :                 rgcount++;
     237             :         }
     238           0 :         if (lgfs2_rgrps_write_final(sdp->device_fd, rgs) != 0) {
     239           0 :                 perror(_("Failed to write final resource group"));
     240           0 :                 return 0;
     241             :         }
     242           0 :         fsync(sdp->device_fd);
     243           0 :         return rgcount;
     244             : }
     245             : 
     246           0 : static char *rindex_buffer(lgfs2_rgrps_t rgs, unsigned count)
     247             : {
     248             :         lgfs2_rgrp_t rg;
     249           0 :         unsigned i = 0;
     250             :         char *buf;
     251             : 
     252           0 :         buf = calloc(count, sizeof(struct gfs2_rindex));
     253           0 :         if (buf == NULL) {
     254           0 :                 perror(__FUNCTION__);
     255           0 :                 exit(EXIT_FAILURE);
     256             :         }
     257           0 :         for (rg = lgfs2_rgrp_first(rgs); rg; rg = lgfs2_rgrp_next(rg)) {
     258           0 :                 lgfs2_rindex_out(rg, buf + (sizeof(struct gfs2_rindex) * i));
     259           0 :                 i++;
     260             :         }
     261           0 :         return buf;
     262             : }
     263             : 
     264             : /**
     265             :  * fix_rindex - Add the new entries to the end of the rindex file.
     266             :  */
     267           0 : static void fix_rindex(int rindex_fd, lgfs2_rgrps_t rgs, unsigned old_rg_count, unsigned rgcount)
     268             : {
     269             :         char *buf;
     270             :         ssize_t count;
     271             :         ssize_t writelen;
     272             :         off_t rindex_size;
     273           0 :         const size_t entrysize = sizeof(struct gfs2_rindex);
     274             : 
     275           0 :         log_info( _("%d new rindex entries.\n"), rgcount);
     276           0 :         buf = rindex_buffer(rgs, rgcount);
     277           0 :         writelen = rgcount * entrysize;
     278             : 
     279           0 :         if (test)
     280           0 :                 goto out;
     281             : 
     282           0 :         rindex_size = lseek(rindex_fd, 0, SEEK_END);
     283           0 :         if (rindex_size != old_rg_count * entrysize) {
     284           0 :                 log_crit(_("Incorrect rindex size. Want %ld (%d resource groups), have %ld\n"),
     285             :                          (long)(old_rg_count * entrysize), old_rg_count,
     286             :                          (long)rindex_size);
     287           0 :                 goto out;
     288             :         }
     289             :         /* Write the first entry separately to ensure there's enough
     290             :            space in the fs for the rest  */
     291           0 :         count = write(rindex_fd, buf, entrysize);
     292           0 :         if (count != entrysize) {
     293           0 :                 log_crit(_("Error writing first new rindex entry; aborted.\n"));
     294           0 :                 if (count > 0)
     295           0 :                         goto trunc;
     296             :                 else
     297           0 :                         goto out;
     298             :         }
     299           0 :         count = write(rindex_fd, (buf + entrysize), (writelen - entrysize));
     300           0 :         if (count != (writelen - entrysize)) {
     301           0 :                 log_crit(_("Error writing new rindex entries; aborted.\n"));
     302           0 :                 if (count > 0)
     303           0 :                         goto trunc;
     304             :                 else
     305           0 :                         goto out;
     306             :         }
     307           0 :         if (fallocate(rindex_fd, FALLOC_FL_KEEP_SIZE, (rindex_size + writelen), entrysize) != 0)
     308           0 :                 perror("fallocate");
     309           0 :         fsync(rindex_fd);
     310           0 : out:
     311           0 :         free(buf);
     312           0 :         return;
     313           0 : trunc:
     314           0 :         count = (count / sizeof(struct gfs2_rindex)) + old_rg_count;
     315           0 :         log_crit(_("truncating rindex to %ld entries\n"),
     316             :                  (long)count * sizeof(struct gfs2_rindex));
     317           0 :         if (ftruncate(rindex_fd, (off_t)count * sizeof(struct gfs2_rindex)))
     318           0 :                 log_crit(_("Could not truncate rindex: %s\n"), strerror(errno));
     319           0 :         free(buf);
     320             : }
     321             : 
     322             : /**
     323             :  * print_info - Print out various bits of (interesting?) information
     324             :  */
     325           0 : static void print_info(struct lgfs2_sbd *sdp, char *device, char *mnt_path)
     326             : {
     327           0 :         log_notice(_("Mount point: %s\n"), mnt_path);
     328           0 :         log_notice(_("Device: %s\n"), device);
     329           0 :         log_notice(_("Size: %"PRIu64" blocks\n"), fssize);
     330           0 :         log_notice(_("Length: %"PRIu64" blocks\n"), sdp->device.length);
     331           0 :         log_notice(_("The file system will grow by %"PRIu64"MB.\n"),
     332             :                    (fsgrowth * sdp->sd_bsize) / MB);
     333           0 : }
     334             : 
     335           0 : static int open_rindex(char *metafs_path, int mode)
     336             : {
     337             :         char *path;
     338             :         int fd;
     339             : 
     340           0 :         if (asprintf(&path, "%s/rindex", metafs_path) < 0) {
     341           0 :                 perror(_("Failed to open rindex"));
     342           0 :                 return -1;
     343             :         }
     344           0 :         fd = open(path, (mode | O_CLOEXEC));
     345           0 :         if (fd < 0) {
     346           0 :                 perror(path);
     347           0 :                 fprintf(stderr, _("Please run fsck.gfs2\n"));
     348             :         }
     349           0 :         free(path);
     350           0 :         return fd;
     351             : }
     352             : 
     353             : #ifndef UNITTESTS
     354             : int main(int argc, char *argv[])
     355             : {
     356             :         struct lgfs2_sbd sbd, *sdp = &sbd;
     357             :         int rindex_fd;
     358             :         int error = EXIT_SUCCESS;
     359             :         int devflags = (test ? O_RDONLY : O_RDWR) | O_CLOEXEC;
     360             : 
     361             :         setlocale(LC_ALL, "");
     362             :         textdomain("gfs2-utils");
     363             :         srandom(time(NULL) ^ getpid());
     364             : 
     365             :         memset(sdp, 0, sizeof(struct lgfs2_sbd));
     366             :         sdp->sd_bsize = LGFS2_DEFAULT_BSIZE;
     367             :         sdp->rgsize = -1;
     368             :         sdp->jsize = LGFS2_DEFAULT_JSIZE;
     369             :         sdp->qcsize = LGFS2_DEFAULT_QCSIZE;
     370             :         sdp->md.journals = 1;
     371             :         decode_arguments(argc, argv, sdp);
     372             : 
     373             :         for(; (argc - optind) > 0; optind++) {
     374             :                 struct metafs mfs = {0};
     375             :                 struct mntent *mnt;
     376             :                 unsigned rgcount;
     377             :                 unsigned old_rg_count;
     378             :                 lgfs2_rgrps_t rgs;
     379             : 
     380             :                 error = lgfs2_open_mnt(argv[optind], O_RDONLY|O_CLOEXEC, &sdp->path_fd,
     381             :                                                        devflags, &sdp->device_fd, &mnt);
     382             :                 if (error != 0) {
     383             :                         fprintf(stderr, _("Error looking up mount '%s': %s\n"), argv[optind], strerror(errno));
     384             :                         exit(EXIT_FAILURE);
     385             :                 }
     386             :                 if (mnt == NULL) {
     387             :                         fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), argv[optind]);
     388             :                         continue;
     389             :                 }
     390             : 
     391             :                 if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo) < 0) {
     392             :                         perror(mnt->mnt_fsname);
     393             :                         exit(EXIT_FAILURE);
     394             :                 }
     395             :                 sdp->sd_bsize = LGFS2_DEFAULT_BSIZE;
     396             :                 if (lgfs2_compute_constants(sdp)) {
     397             :                         log_crit("%s\n", _("Failed to compute file system constants"));
     398             :                         exit(EXIT_FAILURE);
     399             :                 }
     400             :                 if (lgfs2_read_sb(sdp) < 0) {
     401             :                         fprintf(stderr, _("Error reading superblock.\n"));
     402             :                         exit(EXIT_FAILURE);
     403             :                 }
     404             :                 lgfs2_fix_device_geometry(sdp);
     405             :                 mfs.context = copy_context_opt(mnt);
     406             :                 if (mount_gfs2_meta(&mfs, mnt->mnt_dir, (print_level > MSG_NOTICE))) {
     407             :                         perror(_("Failed to mount GFS2 meta file system"));
     408             :                         exit(EXIT_FAILURE);
     409             :                 }
     410             :                 rindex_fd = open_rindex(mfs.path, (test ? O_RDONLY : O_RDWR));
     411             :                 if (rindex_fd < 0) {
     412             :                         cleanup_metafs(&mfs);
     413             :                         exit(EXIT_FAILURE);
     414             :                 }
     415             :                 /* Get master dinode */
     416             :                 sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_meta_dir.in_addr);
     417             :                 if (sdp->master_dir == NULL) {
     418             :                         perror(_("Could not read master directory"));
     419             :                         exit(EXIT_FAILURE);
     420             :                 }
     421             :                 rgs = rgrps_init(sdp);
     422             :                 if (rgs == NULL) {
     423             :                         perror(_("Could not initialise resource groups"));
     424             :                         error = -1;
     425             :                         goto out;
     426             :                 }
     427             :                 /* Fetch the rindex from disk.  We aren't using gfs2 here,  */
     428             :                 /* which means that the bitmaps will most likely be cached  */
     429             :                 /* and therefore out of date.  It shouldn't matter because  */
     430             :                 /* we're only going to write out new RG information after   */
     431             :                 /* the existing RGs, and only write to the index at EOF.    */
     432             :                 log_info(_("Gathering resource group information for %s\n"), argv[optind]);
     433             :                 old_rg_count = lgfs2_rindex_read_fd(rindex_fd, rgs);
     434             :                 if (old_rg_count == 0) {
     435             :                         perror(_("Failed to scan existing resource groups"));
     436             :                         error = -EXIT_FAILURE;
     437             :                         goto out;
     438             :                 }
     439             :                 if (metafs_interrupted)
     440             :                         goto out;
     441             :                 fssize = lgfs2_rgrp_align_addr(rgs, filesystem_size(rgs) + 1);
     442             :                 /* We're done with the old rgs now that we have the fssize and rg count */
     443             :                 lgfs2_rgrps_free(&rgs);
     444             :                 /* Now lets set up the new ones with alignment and all */
     445             :                 rgs = rgrps_init(sdp);
     446             :                 if (rgs == NULL) {
     447             :                         perror(_("Could not initialise new resource groups"));
     448             :                         error = -1;
     449             :                         goto out;
     450             :                 }
     451             :                 fsgrowth = (sdp->device.length - fssize);
     452             :                 rgcount = lgfs2_rgrps_plan(rgs, fsgrowth, ((LGFS2_MAX_RGSIZE << 20) / sdp->sd_bsize));
     453             :                 if (rgcount == 0) {
     454             :                         log_err( _("The calculated resource group size is too small.\n"));
     455             :                         log_err( _("%s has not grown.\n"), argv[optind]);
     456             :                         error = -1;
     457             :                         goto out;
     458             :                 }
     459             :                 print_info(sdp, mnt->mnt_fsname, mnt->mnt_dir);
     460             :                 rgcount = initialize_new_portion(sdp, rgs);
     461             :                 if (rgcount == 0 || metafs_interrupted)
     462             :                         goto out;
     463             :                 fsync(sdp->device_fd);
     464             :                 fix_rindex(rindex_fd, rgs, old_rg_count, rgcount);
     465             :         out:
     466             :                 if (rgs != NULL)
     467             :                         lgfs2_rgrps_free(&rgs);
     468             :                 close(rindex_fd);
     469             :                 cleanup_metafs(&mfs);
     470             :                 close(sdp->device_fd);
     471             : 
     472             :                 if (metafs_interrupted)
     473             :                         break;
     474             :         }
     475             :         close(sdp->path_fd);
     476             :         sync();
     477             :         if (metafs_interrupted) {
     478             :                 log_notice( _("gfs2_grow interrupted.\n"));
     479             :                 exit(1);
     480             :         }
     481             :         log_notice( _("gfs2_grow complete.\n"));
     482             :         return error;
     483             : }
     484             : #endif /* UNITTESTS */

Generated by: LCOV version 1.14