Whamcloud - gitweb
Merge branch 'maint' into next
[tools/e2fsprogs.git] / misc / mk_hugefiles.c
index b7a9840..3caaf1b 100644 (file)
@@ -2,8 +2,6 @@
  * mk_hugefiles.c -- create huge files
  */
 
-#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
-
 #include "config.h"
 #include <stdio.h>
 #include <string.h>
@@ -29,9 +27,14 @@ extern int optind;
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
 #include <libgen.h>
 #include <limits.h>
 #include <blkid/blkid.h>
@@ -43,9 +46,9 @@ extern int optind;
 #include "e2p/e2p.h"
 #include "ext2fs/ext2fs.h"
 #include "util.h"
-#include "profile.h"
-#include "prof_err.h"
-#include "nls-enable.h"
+#include "support/profile.h"
+#include "support/prof_err.h"
+#include "support/nls-enable.h"
 #include "mke2fs.h"
 
 static int uid;
@@ -60,6 +63,32 @@ static char *fn_buf;
 static char *fn_numbuf;
 int zero_hugefile = 1;
 
+static blk64_t
+get_partition_start(const char *device_name EXT2FS_ATTR((unused)))
+{
+#ifdef __linux__
+       unsigned long long start;
+       char            path[128];
+       struct stat     st;
+       FILE            *f;
+       int             n;
+
+       if ((stat(device_name, &st) < 0) || !S_ISBLK(st.st_mode))
+               return 0;
+
+       sprintf(path, "/sys/dev/block/%d:%d/start",
+               major(st.st_rdev), minor(st.st_rdev));
+       f = fopen(path, "r");
+       if (!f)
+               return 0;
+       n = fscanf(f, "%llu", &start);
+       fclose(f);
+       return (n == 1) ? start : 0;
+#else
+       return 0;
+#endif
+}
+
 static errcode_t create_directory(ext2_filsys fs, char *dir,
                                  ext2_ino_t *ret_ino)
 
@@ -148,6 +177,14 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
        if (retval)
                return retval;
 
+       /*
+        * We don't use ext2fs_fallocate() here because hugefiles are
+        * designed to be physically contiguous (if the block group
+        * descriptors are configured to be in a single block at the
+        * beginning of the file system, by using the
+        * packed_meta_blocks layout), with the extent tree blocks
+        * allocated near the beginning of the file system.
+        */
        lblk = 0;
        left = num ? num : 1;
        while (left) {
@@ -184,7 +221,8 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
                        if (retval)
                                com_err(program_name, retval,
                                        _("while zeroing block %llu "
-                                         "for hugefile"), ret_blk);
+                                         "for hugefile"),
+                                       (unsigned long long) ret_blk);
                }
 
                while (n) {
@@ -218,8 +256,9 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
        if (retval)
                goto errout;
        size = (__u64) count * fs->blocksize;
-       inode.i_size = size & 0xffffffff;
-       inode.i_size_high = (size >> 32);
+       retval = ext2fs_inode_size_set(fs, &inode, size);
+       if (retval)
+               goto errout;
 
        retval = ext2fs_write_new_inode(fs, *ino, &inode);
        if (retval)
@@ -273,7 +312,8 @@ static blk64_t calc_overhead(ext2_filsys fs, blk64_t num)
        e_blocks2 = (e_blocks + extents_per_block - 1) / extents_per_block;
        e_blocks3 = (e_blocks2 + extents_per_block - 1) / extents_per_block;
        e_blocks4 = (e_blocks3 + extents_per_block - 1) / extents_per_block;
-       return e_blocks + e_blocks2 + e_blocks3 + e_blocks4;
+       return (e_blocks + e_blocks2 + e_blocks3 + e_blocks4) *
+               EXT2FS_CLUSTER_RATIO(fs);
 }
 
 /*
@@ -297,7 +337,6 @@ static blk64_t get_start_block(ext2_filsys fs, blk64_t slack)
                                                blk, last_blk, &next);
                if (retval)
                        next = last_blk;
-               next--;
 
                if (next - blk > slack) {
                        blk += slack;
@@ -310,24 +349,26 @@ static blk64_t get_start_block(ext2_filsys fs, blk64_t slack)
        return blk;
 }
 
-static blk64_t round_up_align(blk64_t b, unsigned long align)
+static blk64_t round_up_align(blk64_t b, unsigned long align,
+                             blk64_t part_offset)
 {
        unsigned long m;
 
        if (align == 0)
                return b;
-       m = b % align;
+       part_offset = part_offset % align;
+       m = (b + part_offset) % align;
        if (m)
                b += align - m;
        return b;
 }
 
-errcode_t mk_hugefiles(ext2_filsys fs)
+errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
 {
        unsigned long   i;
        ext2_ino_t      dir;
        errcode_t       retval;
-       blk64_t         fs_blocks;
+       blk64_t         fs_blocks, part_offset = 0;
        unsigned long   align;
        int             d, dsize;
        char            *t;
@@ -335,6 +376,9 @@ errcode_t mk_hugefiles(ext2_filsys fs)
        if (!get_bool_from_profile(fs_types, "make_hugefiles", 0))
                return 0;
 
+       if (!ext2fs_has_feature_extents(fs->super))
+               return EXT2_ET_EXTENT_NOT_SUPPORTED;
+
        uid = get_int_from_profile(fs_types, "hugefiles_uid", 0);
        gid = get_int_from_profile(fs_types, "hugefiles_gid", 0);
        fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077);
@@ -348,7 +392,19 @@ errcode_t mk_hugefiles(ext2_filsys fs)
        t = get_string_from_profile(fs_types, "hugefiles_align", "0");
        align = parse_num_blocks2(t, fs->super->s_log_block_size);
        free(t);
-       num_blocks = round_up_align(num_blocks, align);
+       if (get_bool_from_profile(fs_types, "hugefiles_align_disk", 0)) {
+               part_offset = get_partition_start(device_name) /
+                       (fs->blocksize / 512);
+               if (part_offset % EXT2FS_CLUSTER_RATIO(fs)) {
+                       fprintf(stderr,
+                               _("Partition offset of %llu (%uk) blocks "
+                                 "not compatible with cluster size %u.\n"),
+                               (unsigned long long) part_offset, fs->blocksize,
+                               EXT2_CLUSTER_SIZE(fs->super));
+                       exit(1);
+               }
+       }
+       num_blocks = round_up_align(num_blocks, align, 0);
        zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles",
                                              zero_hugefile);
 
@@ -376,10 +432,10 @@ errcode_t mk_hugefiles(ext2_filsys fs)
 
        fs_blocks = ext2fs_free_blocks_count(fs->super);
        if (fs_blocks < num_slack + align)
-               return ENOMEM;
+               return ENOSPC;
        fs_blocks -= num_slack + align;
        if (num_blocks && num_blocks > fs_blocks)
-               return ENOMEM;
+               return ENOSPC;
        if (num_blocks == 0 && num_files == 0)
                num_files = 1;
 
@@ -397,22 +453,23 @@ errcode_t mk_hugefiles(ext2_filsys fs)
                num_blocks = fs_blocks / num_files;
        }
 
-       num_slack += calc_overhead(fs, num_blocks) * num_files;
+       num_slack += (calc_overhead(fs, num_blocks ? num_blocks : fs_blocks) *
+                     num_files);
        num_slack += (num_files / 16) + 1; /* space for dir entries */
        goal = get_start_block(fs, num_slack);
-       goal = round_up_align(goal, align);
+       goal = round_up_align(goal, align, part_offset);
 
        if ((num_blocks ? num_blocks : fs_blocks) >
            (0x80000000UL / fs->blocksize))
-               fs->super->s_feature_ro_compat |=
-                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+               ext2fs_set_feature_large_file(fs->super);
 
        if (!quiet) {
                if (zero_hugefile && verbose)
                        printf("%s", _("Huge files will be zero'ed\n"));
                printf(_("Creating %lu huge file(s) "), num_files);
                if (num_blocks)
-                       printf(_("with %llu blocks each"), num_blocks);
+                       printf(_("with %llu blocks each"),
+                              (unsigned long long) num_blocks);
                fputs(": ", stdout);
        }
        for (i=0; i < num_files; i++) {