LCOV - code coverage report
Current view: top level - mkfs - main_grow.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 0.0 % 179 0
Test Date: 2024-03-07 16:24:06 Functions: 0.0 % 10 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->md.journals = 1;
     368              :         decode_arguments(argc, argv, sdp);
     369              : 
     370              :         for(; (argc - optind) > 0; optind++) {
     371              :                 struct metafs mfs = {0};
     372              :                 struct mntent *mnt;
     373              :                 unsigned rgcount;
     374              :                 unsigned old_rg_count;
     375              :                 lgfs2_rgrps_t rgs;
     376              : 
     377              :                 error = lgfs2_open_mnt(argv[optind], O_RDONLY|O_CLOEXEC, &sdp->path_fd,
     378              :                                                        devflags, &sdp->device_fd, &mnt);
     379              :                 if (error != 0) {
     380              :                         fprintf(stderr, _("Error looking up mount '%s': %s\n"), argv[optind], strerror(errno));
     381              :                         exit(EXIT_FAILURE);
     382              :                 }
     383              :                 if (mnt == NULL) {
     384              :                         fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), argv[optind]);
     385              :                         continue;
     386              :                 }
     387              : 
     388              :                 if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo) < 0) {
     389              :                         perror(mnt->mnt_fsname);
     390              :                         exit(EXIT_FAILURE);
     391              :                 }
     392              :                 sdp->sd_bsize = LGFS2_DEFAULT_BSIZE;
     393              :                 if (lgfs2_compute_constants(sdp)) {
     394              :                         log_crit("%s\n", _("Failed to compute file system constants"));
     395              :                         exit(EXIT_FAILURE);
     396              :                 }
     397              :                 if (lgfs2_read_sb(sdp) < 0) {
     398              :                         fprintf(stderr, _("Error reading superblock.\n"));
     399              :                         exit(EXIT_FAILURE);
     400              :                 }
     401              :                 lgfs2_fix_device_geometry(sdp);
     402              :                 mfs.context = copy_context_opt(mnt);
     403              :                 if (mount_gfs2_meta(&mfs, mnt->mnt_dir, (print_level > MSG_NOTICE))) {
     404              :                         perror(_("Failed to mount GFS2 meta file system"));
     405              :                         exit(EXIT_FAILURE);
     406              :                 }
     407              :                 rindex_fd = open_rindex(mfs.path, (test ? O_RDONLY : O_RDWR));
     408              :                 if (rindex_fd < 0) {
     409              :                         cleanup_metafs(&mfs);
     410              :                         exit(EXIT_FAILURE);
     411              :                 }
     412              :                 /* Get master dinode */
     413              :                 sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_meta_dir.in_addr);
     414              :                 if (sdp->master_dir == NULL) {
     415              :                         perror(_("Could not read master directory"));
     416              :                         exit(EXIT_FAILURE);
     417              :                 }
     418              :                 rgs = rgrps_init(sdp);
     419              :                 if (rgs == NULL) {
     420              :                         perror(_("Could not initialise resource groups"));
     421              :                         error = -1;
     422              :                         goto out;
     423              :                 }
     424              :                 /* Fetch the rindex from disk.  We aren't using gfs2 here,  */
     425              :                 /* which means that the bitmaps will most likely be cached  */
     426              :                 /* and therefore out of date.  It shouldn't matter because  */
     427              :                 /* we're only going to write out new RG information after   */
     428              :                 /* the existing RGs, and only write to the index at EOF.    */
     429              :                 log_info(_("Gathering resource group information for %s\n"), argv[optind]);
     430              :                 old_rg_count = lgfs2_rindex_read_fd(rindex_fd, rgs);
     431              :                 if (old_rg_count == 0) {
     432              :                         perror(_("Failed to scan existing resource groups"));
     433              :                         error = -EXIT_FAILURE;
     434              :                         goto out;
     435              :                 }
     436              :                 if (metafs_interrupted)
     437              :                         goto out;
     438              :                 fssize = lgfs2_rgrp_align_addr(rgs, filesystem_size(rgs) + 1);
     439              :                 /* We're done with the old rgs now that we have the fssize and rg count */
     440              :                 lgfs2_rgrps_free(&rgs);
     441              :                 /* Now lets set up the new ones with alignment and all */
     442              :                 rgs = rgrps_init(sdp);
     443              :                 if (rgs == NULL) {
     444              :                         perror(_("Could not initialise new resource groups"));
     445              :                         error = -1;
     446              :                         goto out;
     447              :                 }
     448              :                 fsgrowth = (sdp->device.length - fssize);
     449              :                 rgcount = lgfs2_rgrps_plan(rgs, fsgrowth, ((LGFS2_MAX_RGSIZE << 20) / sdp->sd_bsize));
     450              :                 if (rgcount == 0) {
     451              :                         log_err( _("The calculated resource group size is too small.\n"));
     452              :                         log_err( _("%s has not grown.\n"), argv[optind]);
     453              :                         error = -1;
     454              :                         goto out;
     455              :                 }
     456              :                 print_info(sdp, mnt->mnt_fsname, mnt->mnt_dir);
     457              :                 rgcount = initialize_new_portion(sdp, rgs);
     458              :                 if (rgcount == 0 || metafs_interrupted)
     459              :                         goto out;
     460              :                 fsync(sdp->device_fd);
     461              :                 fix_rindex(rindex_fd, rgs, old_rg_count, rgcount);
     462              :         out:
     463              :                 if (rgs != NULL)
     464              :                         lgfs2_rgrps_free(&rgs);
     465              :                 close(rindex_fd);
     466              :                 cleanup_metafs(&mfs);
     467              :                 close(sdp->device_fd);
     468              : 
     469              :                 if (metafs_interrupted)
     470              :                         break;
     471              :         }
     472              :         close(sdp->path_fd);
     473              :         sync();
     474              :         if (metafs_interrupted) {
     475              :                 log_notice( _("gfs2_grow interrupted.\n"));
     476              :                 exit(1);
     477              :         }
     478              :         log_notice( _("gfs2_grow complete.\n"));
     479              :         return error;
     480              : }
     481              : #endif /* UNITTESTS */
        

Generated by: LCOV version 2.0-1