Whamcloud - gitweb
mke2fs: use ext2fs_get_device_size2() on all platforms
[tools/e2fsprogs.git] / misc / mk_hugefiles.c
index 5882394..0280b41 100644 (file)
@@ -32,7 +32,9 @@ 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
@@ -66,7 +68,7 @@ static char *fn_buf;
 static char *fn_numbuf;
 int zero_hugefile = 1;
 
-#define SYSFS_PATH_LEN 256
+#define SYSFS_PATH_LEN 300
 typedef char sysfs_path_t[SYSFS_PATH_LEN];
 
 #ifndef HAVE_SNPRINTF
@@ -262,8 +264,12 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
 
 {
        errcode_t               retval;
+       blk64_t                 lblk, bend = 0;
+       __u64                   size;
+       blk64_t                 left;
+       blk64_t                 count = 0;
        struct ext2_inode       inode;
-       int                     falloc_flags;
+       ext2_extent_handle_t    handle;
 
        retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino);
        if (retval)
@@ -283,20 +289,94 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
 
        ext2fs_inode_alloc_stats2(fs, *ino, +1, 0);
 
-       if (ext2fs_has_feature_extents(fs->super))
-               inode.i_flags |= EXT4_EXTENTS_FL;
-
-       falloc_flags = EXT2_FALLOCATE_FORCE_INIT;
-       if (zero_hugefile)
-               falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS;
-       retval = ext2fs_fallocate(fs, falloc_flags, *ino, &inode, goal, 0, num);
+       retval = ext2fs_extent_open2(fs, *ino, &inode, &handle);
        if (retval)
                return retval;
-       retval = ext2fs_inode_size_set(fs, &inode, num * fs->blocksize);
+
+       /*
+        * 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) {
+               blk64_t pblk, end;
+               blk64_t n = left;
+
+               retval =  ext2fs_find_first_zero_block_bitmap2(fs->block_map,
+                       goal, ext2fs_blocks_count(fs->super) - 1, &end);
+               if (retval)
+                       goto errout;
+               goal = end;
+
+               retval =  ext2fs_find_first_set_block_bitmap2(fs->block_map, goal,
+                              ext2fs_blocks_count(fs->super) - 1, &bend);
+               if (retval == ENOENT) {
+                       bend = ext2fs_blocks_count(fs->super);
+                       if (num == 0)
+                               left = 0;
+               }
+               if (!num || bend - goal < left)
+                       n = bend - goal;
+               pblk = goal;
+               if (num)
+                       left -= n;
+               goal += n;
+               count += n;
+               ext2fs_block_alloc_stats_range(fs, pblk, n, +1);
+
+               if (zero_hugefile) {
+                       blk64_t ret_blk;
+                       retval = ext2fs_zero_blocks2(fs, pblk, n,
+                                                    &ret_blk, NULL);
+
+                       if (retval)
+                               com_err(program_name, retval,
+                                       _("while zeroing block %llu "
+                                         "for hugefile"),
+                                       (unsigned long long) ret_blk);
+               }
+
+               while (n) {
+                       blk64_t l = n;
+                       struct ext2fs_extent newextent;
+
+                       if (l > EXT_INIT_MAX_LEN)
+                               l = EXT_INIT_MAX_LEN;
+
+                       newextent.e_len = l;
+                       newextent.e_pblk = pblk;
+                       newextent.e_lblk = lblk;
+                       newextent.e_flags = 0;
+
+                       retval = ext2fs_extent_insert(handle,
+                                       EXT2_EXTENT_INSERT_AFTER, &newextent);
+                       if (retval)
+                               return retval;
+                       pblk += l;
+                       lblk += l;
+                       n -= l;
+               }
+       }
+
+       retval = ext2fs_read_inode(fs, *ino, &inode);
        if (retval)
-               return retval;
+               goto errout;
 
-       retval = ext2fs_write_inode(fs, *ino, &inode);
+       retval = ext2fs_iblk_add_blocks(fs, &inode,
+                                       count / EXT2FS_CLUSTER_RATIO(fs));
+       if (retval)
+               goto errout;
+       size = (__u64) count * fs->blocksize;
+       retval = ext2fs_inode_size_set(fs, &inode, size);
+       if (retval)
+               goto errout;
+
+       retval = ext2fs_write_new_inode(fs, *ino, &inode);
        if (retval)
                goto errout;
 
@@ -314,7 +394,13 @@ retry:
                goto retry;
        }
 
+       if (retval)
+               goto errout;
+
 errout:
+       if (handle)
+               ext2fs_extent_free(handle);
+
        return retval;
 }
 
@@ -342,7 +428,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);
 }
 
 /*
@@ -428,7 +515,7 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
                        fprintf(stderr,
                                _("Partition offset of %llu (%uk) blocks "
                                  "not compatible with cluster size %u.\n"),
-                               part_offset, fs->blocksize,
+                               (unsigned long long) part_offset, fs->blocksize,
                                EXT2_CLUSTER_SIZE(fs->super));
                        exit(1);
                }
@@ -482,7 +569,8 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
                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, part_offset);
@@ -496,11 +584,10 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
                        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);
        }
-       if (num_blocks == 0)
-               num_blocks = ext2fs_blocks_count(fs->super) - goal;
        for (i=0; i < num_files; i++) {
                ext2_ino_t ino;