Whamcloud - gitweb
LU-6722 jbd: double minimum journal size for RHEL7
[tools/e2fsprogs.git] / lib / ext2fs / mkjournal.c
index f47f71e..4a71155 100644 (file)
@@ -12,6 +12,7 @@
 #include "config.h"
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
+#ifdef __linux__
+#include <sys/utsname.h>
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
 
 #include "ext2_fs.h"
 #include "e2p/e2p.h"
  * This function automatically sets up the journal superblock and
  * returns it as an allocated block.
  */
-errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
-                                          __u32 num_blocks, int flags,
-                                          char  **ret_jsb)
+errcode_t ext2fs_create_journal_superblock2(ext2_filsys fs,
+                                          struct ext2fs_journal_params *jparams,
+                                          int flags, char **ret_jsb)
 {
        errcode_t               retval;
        journal_superblock_t    *jsb;
 
-       if (num_blocks < JBD2_MIN_JOURNAL_BLOCKS)
+       if (jparams->num_journal_blocks < JBD2_MIN_JOURNAL_BLOCKS)
                return EXT2_ET_JOURNAL_TOO_SMALL;
 
        if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
@@ -64,10 +69,11 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
        else
                jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
        jsb->s_blocksize = htonl(fs->blocksize);
-       jsb->s_maxlen = htonl(num_blocks);
+       jsb->s_maxlen = htonl(jparams->num_journal_blocks + jparams->num_fc_blocks);
        jsb->s_nr_users = htonl(1);
        jsb->s_first = htonl(1);
        jsb->s_sequence = htonl(1);
+       jsb->s_num_fc_blks = htonl(jparams->num_fc_blocks);
        memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
        /*
         * If we're creating an external journal device, we need to
@@ -82,20 +88,32 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
        return 0;
 }
 
+errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, __u32 num_blocks,
+                                       int flags, char **ret_sb)
+{
+       struct ext2fs_journal_params jparams;
+
+       jparams.num_journal_blocks = num_blocks;
+       jparams.num_fc_blocks = 0;
+
+       return ext2fs_create_journal_superblock2(fs, &jparams, flags, ret_sb);
+}
+
 /*
  * This function writes a journal using POSIX routines.  It is used
  * for creating external journals and creating journals on live
  * filesystems.
  */
 static errcode_t write_journal_file(ext2_filsys fs, char *filename,
-                                   blk_t num_blocks, int flags)
+                                   struct ext2fs_journal_params *jparams,
+                                   int flags)
 {
        errcode_t       retval;
        char            *buf = 0;
        int             fd, ret_size;
        blk_t           i;
 
-       if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
+       if ((retval = ext2fs_create_journal_superblock2(fs, jparams, flags,
                                                       &buf)))
                return retval;
 
@@ -119,7 +137,7 @@ static errcode_t write_journal_file(ext2_filsys fs, char *filename,
        if (flags & EXT2_MKJOURNAL_LAZYINIT)
                goto success;
 
-       for (i = 1; i < num_blocks; i++) {
+       for (i = 1; i < jparams->num_journal_blocks + jparams->num_fc_blocks; i++) {
                ret_size = write(fd, buf, fs->blocksize);
                if (ret_size < 0) {
                        retval = errno;
@@ -262,7 +280,8 @@ static blk64_t get_midpoint_journal_block(ext2_filsys fs)
  * This function creates a journal using direct I/O routines.
  */
 static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
-                                    blk_t num_blocks, blk64_t goal, int flags)
+                                    struct ext2fs_journal_params *jparams,
+                                    blk64_t goal, int flags)
 {
        char                    *buf;
        errcode_t               retval;
@@ -271,7 +290,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
        int                     falloc_flags = EXT2_FALLOCATE_FORCE_INIT;
        blk64_t                 zblk;
 
-       if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
+       if ((retval = ext2fs_create_journal_superblock2(fs, jparams, flags,
                                                       &buf)))
                return retval;
 
@@ -295,7 +314,8 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
        if (!(flags & EXT2_MKJOURNAL_LAZYINIT))
                falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS;
 
-       inode_size = (unsigned long long)fs->blocksize * num_blocks;
+       inode_size = (unsigned long long)fs->blocksize *
+                       (jparams->num_journal_blocks + jparams->num_fc_blocks);
        inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
        inode.i_links_count = 1;
        inode.i_mode = LINUX_S_IFREG | 0600;
@@ -304,7 +324,8 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
                goto out2;
 
        retval = ext2fs_fallocate(fs, falloc_flags, journal_ino,
-                                 &inode, goal, 0, num_blocks);
+                                 &inode, goal, 0,
+                                 jparams->num_journal_blocks + jparams->num_fc_blocks);
        if (retval)
                goto out2;
 
@@ -330,6 +351,54 @@ out2:
        return retval;
 }
 
+#ifdef __linux__
+static int parse_version_number(const char *s)
+{
+       int     major, minor, rev;
+       char    *endptr;
+       const char *cp = s;
+
+       if (!s)
+               return 0;
+       major = strtol(cp, &endptr, 10);
+       if (cp == endptr || *endptr != '.')
+               return 0;
+       cp = endptr + 1;
+       minor = strtol(cp, &endptr, 10);
+       if (cp == endptr || *endptr != '.')
+               return 0;
+       cp = endptr + 1;
+       rev = strtol(cp, &endptr, 10);
+       if (cp == endptr)
+               return 0;
+       return KERNEL_VERSION(major, minor, rev);
+}
+
+int ext2fs_is_before_linux_ver(unsigned int major, unsigned int minor,
+                              unsigned int rev)
+{
+       struct          utsname ut;
+       static int      linux_version_code = -1;
+
+       if (uname(&ut)) {
+               perror("uname");
+               exit(1);
+       }
+       if (linux_version_code < 0)
+               linux_version_code = parse_version_number(ut.release);
+       if (linux_version_code == 0)
+               return 0;
+
+       return linux_version_code < KERNEL_VERSION(major, minor, rev);
+}
+#else
+int ext2fs_is_before_linux_ver(unsigned int major, unsigned int minor,
+                              unsigned int rev)
+{
+       return 0;
+}
+#endif
+
 /*
  * Find a reasonable journal file size (in blocks) given the number of blocks
  * in the filesystem.  For very small filesystems, it is not reasonable to
@@ -341,8 +410,10 @@ int ext2fs_default_journal_size(__u64 num_blocks)
 {
        if (num_blocks < 2048)
                return -1;
-       if (num_blocks < 32768)         /* 128 MB */
+       if (num_blocks <= 8192)         /* 32 MB */
                return (1024);                  /* 4 MB */
+       if (num_blocks < 32768)         /* 128 MB */
+               return (2048);                  /* 8 MB */
        if (num_blocks < 256*1024)      /* 1 GB */
                return (4096);                  /* 16 MB */
        if (num_blocks < 512*1024)      /* 2 GB */
@@ -358,6 +429,43 @@ int ext2fs_default_journal_size(__u64 num_blocks)
        return 262144;                          /* 1 GB */
 }
 
+errcode_t ext2fs_get_journal_params(struct ext2fs_journal_params *params,
+               ext2_filsys fs)
+{
+       blk_t total_blks;
+       int ret;
+
+       memset(params, 0, sizeof(*params));
+       if (ext2fs_has_feature_journal_dev(fs->super)) {
+               total_blks = ext2fs_blocks_count(fs->super);
+               if (total_blks < JBD2_MIN_JOURNAL_BLOCKS)
+                       return EXT2_ET_JOURNAL_TOO_SMALL;
+
+               if (!ext2fs_has_feature_fast_commit(fs->super)) {
+                       params->num_journal_blocks = total_blks;
+                       params->num_fc_blocks = 0;
+                       return 0;
+               }
+               params->num_journal_blocks = ext2fs_blocks_count(fs->super) *
+                               EXT2_JOURNAL_TO_FC_BLKS_RATIO /
+                               (EXT2_JOURNAL_TO_FC_BLKS_RATIO + 1);
+               if (JBD2_MIN_JOURNAL_BLOCKS > params->num_journal_blocks)
+                       params->num_journal_blocks = JBD2_MIN_JOURNAL_BLOCKS;
+               params->num_fc_blocks = total_blks - params->num_journal_blocks;
+               return 0;
+       }
+
+       ret = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super));
+       if (ret < 0)
+               return EXT2_ET_JOURNAL_TOO_SMALL;
+
+       params->num_journal_blocks = ret;
+       if (ext2fs_has_feature_fast_commit(fs->super))
+               params->num_fc_blocks = params->num_journal_blocks /
+                       EXT2_JOURNAL_TO_FC_BLKS_RATIO;
+       return 0;
+}
+
 int ext2fs_journal_sb_start(int blocksize)
 {
        if (blocksize == EXT2_MIN_BLOCK_SIZE)
@@ -434,7 +542,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
  * POSIX routines if the filesystem is mounted, or using direct I/O
  * functions if it is not.
  */
-errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
+errcode_t ext2fs_add_journal_inode3(ext2_filsys fs, struct ext2fs_journal_params *jparams,
                                    blk64_t goal, int flags)
 {
        errcode_t               retval;
@@ -470,7 +578,7 @@ errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
                        retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
                        close(fd);
                        if (retval)
-                               return retval;
+                               return errno;
                }
 #endif
 #endif
@@ -486,7 +594,7 @@ errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
                 * filesystems is extremely rare these days...  Ignore it. */
                flags &= ~EXT2_MKJOURNAL_LAZYINIT;
 
-               if ((retval = write_journal_file(fs, jfile, num_blocks, flags)))
+               if ((retval = write_journal_file(fs, jfile, jparams, flags)))
                        goto errout;
 
                /* Get inode number of the journal file */
@@ -528,7 +636,7 @@ errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
                }
                journal_ino = EXT2_JOURNAL_INO;
                if ((retval = write_journal_inode(fs, journal_ino,
-                                                 num_blocks, goal, flags)))
+                                                 jparams, goal, flags)))
                        return retval;
        }
 
@@ -546,6 +654,18 @@ errout:
        return retval;
 }
 
+errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
+                                   blk64_t goal, int flags)
+{
+       struct ext2fs_journal_params jparams;
+       errcode_t ret;
+
+       jparams.num_journal_blocks = num_blocks;
+       jparams.num_fc_blocks = 0;
+
+       return ext2fs_add_journal_inode3(fs, &jparams, goal, flags);
+}
+
 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
 {
        return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags);