Commit 5e1f8c9e20a92743eefc9a82c2db835213905e26

Authored by Theodore Ts'o
1 parent 8f72fbdf0d

ext3: Add support for non-native signed/unsigned htree hash algorithms

The original ext3 hash algorithms assumed that variables of type char
were signed, as God and K&R intended.  Unfortunately, this assumption
is not true on some architectures.  Userspace support for marking
filesystems with non-native signed/unsigned chars was added two years
ago, but the kernel-side support was never added (until now).

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: akpm@linux-foundation.org
Cc: linux-kernel@vger.kernel.org

Showing 5 changed files with 114 additions and 11 deletions Side-by-side Diff

... ... @@ -35,23 +35,43 @@
35 35  
36 36  
37 37 /* The old legacy hash */
38   -static __u32 dx_hack_hash (const char *name, int len)
  38 +static __u32 dx_hack_hash_unsigned(const char *name, int len)
39 39 {
40   - __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
  40 + __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
  41 + const unsigned char *ucp = (const unsigned char *) name;
  42 +
41 43 while (len--) {
42   - __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
  44 + hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373));
43 45  
44   - if (hash & 0x80000000) hash -= 0x7fffffff;
  46 + if (hash & 0x80000000)
  47 + hash -= 0x7fffffff;
45 48 hash1 = hash0;
46 49 hash0 = hash;
47 50 }
48   - return (hash0 << 1);
  51 + return hash0 << 1;
49 52 }
50 53  
51   -static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
  54 +static __u32 dx_hack_hash_signed(const char *name, int len)
52 55 {
  56 + __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
  57 + const signed char *scp = (const signed char *) name;
  58 +
  59 + while (len--) {
  60 + hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373));
  61 +
  62 + if (hash & 0x80000000)
  63 + hash -= 0x7fffffff;
  64 + hash1 = hash0;
  65 + hash0 = hash;
  66 + }
  67 + return hash0 << 1;
  68 +}
  69 +
  70 +static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num)
  71 +{
53 72 __u32 pad, val;
54 73 int i;
  74 + const signed char *scp = (const signed char *) msg;
55 75  
56 76 pad = (__u32)len | ((__u32)len << 8);
57 77 pad |= pad << 16;
58 78  
... ... @@ -59,10 +79,38 @@
59 79 val = pad;
60 80 if (len > num*4)
61 81 len = num * 4;
  82 + for (i = 0; i < len; i++) {
  83 + if ((i % 4) == 0)
  84 + val = pad;
  85 + val = ((int) scp[i]) + (val << 8);
  86 + if ((i % 4) == 3) {
  87 + *buf++ = val;
  88 + val = pad;
  89 + num--;
  90 + }
  91 + }
  92 + if (--num >= 0)
  93 + *buf++ = val;
  94 + while (--num >= 0)
  95 + *buf++ = pad;
  96 +}
  97 +
  98 +static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num)
  99 +{
  100 + __u32 pad, val;
  101 + int i;
  102 + const unsigned char *ucp = (const unsigned char *) msg;
  103 +
  104 + pad = (__u32)len | ((__u32)len << 8);
  105 + pad |= pad << 16;
  106 +
  107 + val = pad;
  108 + if (len > num*4)
  109 + len = num * 4;
62 110 for (i=0; i < len; i++) {
63 111 if ((i % 4) == 0)
64 112 val = pad;
65   - val = msg[i] + (val << 8);
  113 + val = ((int) ucp[i]) + (val << 8);
66 114 if ((i % 4) == 3) {
67 115 *buf++ = val;
68 116 val = pad;
... ... @@ -95,6 +143,8 @@
95 143 const char *p;
96 144 int i;
97 145 __u32 in[8], buf[4];
  146 + void (*str2hashbuf)(const char *, int, __u32 *, int) =
  147 + str2hashbuf_signed;
98 148  
99 149 /* Initialize the default seed for the hash checksum functions */
100 150 buf[0] = 0x67452301;
101 151  
102 152  
103 153  
... ... @@ -113,13 +163,18 @@
113 163 }
114 164  
115 165 switch (hinfo->hash_version) {
  166 + case DX_HASH_LEGACY_UNSIGNED:
  167 + hash = dx_hack_hash_unsigned(name, len);
  168 + break;
116 169 case DX_HASH_LEGACY:
117   - hash = dx_hack_hash(name, len);
  170 + hash = dx_hack_hash_signed(name, len);
118 171 break;
  172 + case DX_HASH_HALF_MD4_UNSIGNED:
  173 + str2hashbuf = str2hashbuf_unsigned;
119 174 case DX_HASH_HALF_MD4:
120 175 p = name;
121 176 while (len > 0) {
122   - str2hashbuf(p, len, in, 8);
  177 + (*str2hashbuf)(p, len, in, 8);
123 178 half_md4_transform(buf, in);
124 179 len -= 32;
125 180 p += 32;
126 181  
... ... @@ -127,10 +182,12 @@
127 182 minor_hash = buf[2];
128 183 hash = buf[1];
129 184 break;
  185 + case DX_HASH_TEA_UNSIGNED:
  186 + str2hashbuf = str2hashbuf_unsigned;
130 187 case DX_HASH_TEA:
131 188 p = name;
132 189 while (len > 0) {
133   - str2hashbuf(p, len, in, 4);
  190 + (*str2hashbuf)(p, len, in, 4);
134 191 TEA_transform(buf, in);
135 192 len -= 16;
136 193 p += 16;
... ... @@ -368,6 +368,8 @@
368 368 goto fail;
369 369 }
370 370 hinfo->hash_version = root->info.hash_version;
  371 + if (hinfo->hash_version <= DX_HASH_TEA)
  372 + hinfo->hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned;
371 373 hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
372 374 if (entry)
373 375 ext3fs_dirhash(entry->name, entry->len, hinfo);
... ... @@ -636,6 +638,9 @@
636 638 dir = dir_file->f_path.dentry->d_inode;
637 639 if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
638 640 hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
  641 + if (hinfo.hash_version <= DX_HASH_TEA)
  642 + hinfo.hash_version +=
  643 + EXT3_SB(dir->i_sb)->s_hash_unsigned;
639 644 hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
640 645 count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
641 646 start_hash, start_minor_hash);
... ... @@ -1398,6 +1403,8 @@
1398 1403  
1399 1404 /* Initialize as for dx_probe */
1400 1405 hinfo.hash_version = root->info.hash_version;
  1406 + if (hinfo.hash_version <= DX_HASH_TEA)
  1407 + hinfo.hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned;
1401 1408 hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
1402 1409 ext3fs_dirhash(name, namelen, &hinfo);
1403 1410 frame = frames;
... ... @@ -1744,6 +1744,18 @@
1744 1744 for (i=0; i < 4; i++)
1745 1745 sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
1746 1746 sbi->s_def_hash_version = es->s_def_hash_version;
  1747 + i = le32_to_cpu(es->s_flags);
  1748 + if (i & EXT2_FLAGS_UNSIGNED_HASH)
  1749 + sbi->s_hash_unsigned = 3;
  1750 + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
  1751 +#ifdef __CHAR_UNSIGNED__
  1752 + es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
  1753 + sbi->s_hash_unsigned = 3;
  1754 +#else
  1755 + es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
  1756 +#endif
  1757 + sb->s_dirt = 1;
  1758 + }
1747 1759  
1748 1760 if (sbi->s_blocks_per_group > blocksize * 8) {
1749 1761 printk (KERN_ERR
include/linux/ext3_fs.h
... ... @@ -354,6 +354,13 @@
354 354 #define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */
355 355  
356 356 /*
  357 + * Misc. filesystem flags
  358 + */
  359 +#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
  360 +#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
  361 +#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
  362 +
  363 +/*
357 364 * Mount flags
358 365 */
359 366 #define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */
... ... @@ -489,7 +496,23 @@
489 496 __u16 s_reserved_word_pad;
490 497 __le32 s_default_mount_opts;
491 498 __le32 s_first_meta_bg; /* First metablock block group */
492   - __u32 s_reserved[190]; /* Padding to the end of the block */
  499 + __le32 s_mkfs_time; /* When the filesystem was created */
  500 + __le32 s_jnl_blocks[17]; /* Backup of the journal inode */
  501 + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
  502 +/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
  503 + __le32 s_r_blocks_count_hi; /* Reserved blocks count */
  504 + __le32 s_free_blocks_count_hi; /* Free blocks count */
  505 + __le16 s_min_extra_isize; /* All inodes have at least # bytes */
  506 + __le16 s_want_extra_isize; /* New inodes should reserve # bytes */
  507 + __le32 s_flags; /* Miscellaneous flags */
  508 + __le16 s_raid_stride; /* RAID stride */
  509 + __le16 s_mmp_interval; /* # seconds to wait in MMP checking */
  510 + __le64 s_mmp_block; /* Block for multi-mount protection */
  511 + __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
  512 + __u8 s_log_groups_per_flex; /* FLEX_BG group size */
  513 + __u8 s_reserved_char_pad2;
  514 + __le16 s_reserved_pad;
  515 + __u32 s_reserved[162]; /* Padding to the end of the block */
493 516 };
494 517  
495 518 #ifdef __KERNEL__
... ... @@ -694,6 +717,9 @@
694 717 #define DX_HASH_LEGACY 0
695 718 #define DX_HASH_HALF_MD4 1
696 719 #define DX_HASH_TEA 2
  720 +#define DX_HASH_LEGACY_UNSIGNED 3
  721 +#define DX_HASH_HALF_MD4_UNSIGNED 4
  722 +#define DX_HASH_TEA_UNSIGNED 5
697 723  
698 724 #ifdef __KERNEL__
699 725  
include/linux/ext3_fs_sb.h
... ... @@ -57,6 +57,7 @@
57 57 u32 s_next_generation;
58 58 u32 s_hash_seed[4];
59 59 int s_def_hash_version;
  60 + int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */
60 61 struct percpu_counter s_freeblocks_counter;
61 62 struct percpu_counter s_freeinodes_counter;
62 63 struct percpu_counter s_dirs_counter;