Whamcloud - gitweb
Fix potential 2**32-1 overflow by using e2p_percent()
authorTheodore Ts'o <tytso@mit.edu>
Wed, 30 Aug 2006 07:08:13 +0000 (03:08 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 30 Aug 2006 07:08:13 +0000 (03:08 -0400)
Add a new functiom, e2p_percent(), which correct calculates the percentage
of a number based on a given percentage, without worrying about overflow
issues.  This is used where we calculate the number of reserved blocks using
a percentage of the total number of blocks in a filesystem.

Based on patches from Eric Sandeen, but generalized to use this new function.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Eric Sandeen <esandeen@redhat.com>
lib/e2p/ChangeLog
lib/e2p/Makefile.in
lib/e2p/e2p.h
lib/e2p/percent.c [new file with mode: 0644]
misc/ChangeLog
misc/mke2fs.c
misc/tune2fs.c
resize/ChangeLog
resize/online.c
resize/resize2fs.c

index 4dfaba7..4883401 100644 (file)
@@ -1,3 +1,9 @@
+2006-08-30  Theodore Tso  <tytso@mit.edu>
+
+       * percent.c (e2p_percent): Add a new function which accurate and
+               without risk of overflow calculates a percentage of a base
+               number.
+
 2006-08-05  Theodore Tso  <tytso@mit.edu>
 
        * pf.c: Add support for EXT4_EXTENTS_FL flag.
index 6dd3922..494ecd2 100644 (file)
@@ -19,7 +19,7 @@ all:: e2p.pc
 OBJS=          feature.o fgetflags.o fsetflags.o fgetversion.o fsetversion.o \
                getflags.o getversion.o hashstr.o iod.o ls.o mntopts.o \
                parse_num.o pe.o pf.o ps.o setflags.o setversion.o uuid.o \
-               ostype.o 
+               ostype.o percent.o
 
 SRCS=          $(srcdir)/feature.c $(srcdir)/fgetflags.c \
                $(srcdir)/fsetflags.c $(srcdir)/fgetversion.c \
@@ -28,7 +28,7 @@ SRCS=         $(srcdir)/feature.c $(srcdir)/fgetflags.c \
                $(srcdir)/ls.c $(srcdir)/mntopts.c $(srcdir)/parse_num.c \
                $(srcdir)/pe.c $(srcdir)/pf.c $(srcdir)/ps.c \
                $(srcdir)/setflags.c $(srcdir)/setversion.c $(srcdir)/uuid.c \
-               $(srcdir)/ostype.c
+               $(srcdir)/ostype.c $(srcdir)/percent.o
 HFILES= e2p.h
 
 LIBRARY= libe2p
index d208b46..5d9131f 100644 (file)
@@ -50,3 +50,5 @@ unsigned long parse_num_blocks(const char *arg, int log_block_size);
 
 char *e2p_os2string(int os_type);
 int e2p_string2os(char *str);
+
+unsigned int e2p_percent(int percent, unsigned int base);
diff --git a/lib/e2p/percent.c b/lib/e2p/percent.c
new file mode 100644 (file)
index 0000000..f4497b6
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * percent.c           - Take percentage of a number
+ *
+ * Copyright (C) 2006  Theodore Ts'o <tytso@mit.edu>
+ * 
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+#include "e2p.h"
+
+#include <stdlib.h>
+
+/*
+ * We work really hard to calculate this accurately, while avoiding
+ * an overflow.  "Is there a hyphen in anal-retentive?"  :-)
+ */
+unsigned int e2p_percent(int percent, unsigned int base)
+{
+       unsigned int mask = ~((1 << (sizeof(unsigned int) - 1) * 8) - 1);
+
+       if (100 % percent == 0)
+               return base / (100 / percent);
+       if (mask & base) 
+               return (base / 100) * percent;
+       return base * percent / 100;
+}
+
+#ifdef DEBUG
+#include <unistd.h>
+#include <stdio.h>
+
+main(int argc, char **argv)
+{
+       unsigned int base;
+       int percent;
+       char *p;
+       int log_block_size = 0;
+
+       if (argc != 3) {
+               fprintf(stderr, "Usage: %s percent base\n", argv[0]);
+               exit(1);
+       }
+
+       percent = strtoul(argv[1], &p, 0);
+       if (p[0] && p[1]) {
+               fprintf(stderr, "Bad percent: %s\n", argv[1]);
+               exit(1);
+       }
+       
+       base = strtoul(argv[2], &p, 0);
+       if (p[0] && p[1]) {
+               fprintf(stderr, "Bad base: %s\n", argv[2]);
+               exit(1);
+       }
+
+       printf("%d percent of %u is %u.\n", percent, base,
+              e2p_percent(percent, base));
+
+       exit(0);
+}
+#endif
index 4db1c6d..b6a9c51 100644 (file)
@@ -1,5 +1,9 @@
 2006-08-30  Theodore Tso  <tytso@mit.edu>
 
+       * tune2fs.c (main), mke2fs.c (PRS): Use e2p_percent to properly
+               calculate the number of reserved blocks without worrying
+               about overflow.
+
        * Makefile.in (resize2fs): Remove unused (and bogus) resize2fs
                rule, which shouldn't be in misc/Makefile.in
 
index a581ef0..01ef546 100644 (file)
@@ -1447,8 +1447,8 @@ static void PRS(int argc, char *argv[])
        /*
         * Calculate number of blocks to reserve
         */
-       fs_param.s_r_blocks_count = (fs_param.s_blocks_count * reserved_ratio)
-               / 100;
+       fs_param.s_r_blocks_count = e2p_percent(reserved_ratio, 
+                                               fs_param.s_blocks_count);
 }
 
 int main (int argc, char *argv[])
index a0fcf37..d5b9eb3 100644 (file)
@@ -823,7 +823,8 @@ int main (int argc, char ** argv)
                printf (_("Setting interval between checks to %lu seconds\n"), interval);
        }
        if (m_flag) {
-               sb->s_r_blocks_count = sb->s_blocks_count * reserved_ratio /100;
+               sb->s_r_blocks_count = e2p_percent(reserved_ratio,
+                                                  sb->s_blocks_count);
                ext2fs_mark_super_dirty(fs);
                printf (_("Setting reserved blocks percentage to %g%% (%u blocks)\n"),
                        reserved_ratio, sb->s_r_blocks_count);
index dea9ba6..b1c0794 100644 (file)
@@ -1,5 +1,9 @@
 2006-08-30  Theodore Tso  <tytso@mit.edu>
 
+       * resize2fs.c (adjust_fs_info), online.c (online_resize_fs): Use
+               e2p_percent to properly calculate the number of reserved
+               blocks without worrying about overflow.
+
        * resize2fs.c (ext2fs_calculate_summary_stats): Fix potential
                overflow problems when the number of blocks is close to
                2**31.
index 45262b1..7701150 100644 (file)
@@ -107,7 +107,8 @@ errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt,
                                sb->s_first_data_block - 
                                (i * sb->s_blocks_per_group);
                }
-               input.reserved_blocks = input.blocks_count * r_frac / 100;
+               input.reserved_blocks = e2p_percent(r_frac, 
+                                                   input.blocks_count);
 
 #if 0
                printf("new block bitmap is at 0x%04x\n", input.block_bitmap);
index 74b517b..7d3bde9 100644 (file)
@@ -245,8 +245,8 @@ retry:
         */
        blk = old_fs->super->s_r_blocks_count * 100 /
                old_fs->super->s_blocks_count;
-       fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
-                                      / 100);
+       fs->super->s_r_blocks_count = e2p_percent(blk, 
+                                                 fs->super->s_blocks_count);
 
        /*
         * Adjust the bitmaps for size