ext4: fix extent status tree regression for file systems > 512GB
authorTheodore Ts'o <tytso@mit.edu>
Wed, 27 Feb 2013 19:54:37 +0000 (14:54 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 27 Feb 2013 19:54:37 +0000 (14:54 -0500)
This fixes a regression introduced by commit f7fec032aa782.  The
problem was that the extents status flags caused us to mask out block
numbers smaller than 2**28 blocks.  Since we didn't test with file
systems smaller than 512GB, we didn't notice this during the
development cycle.

A typical failure looks like this:

EXT4-fs error (device sdb1): htree_dirblock_to_tree:919: inode #172235804: block
152052301: comm ls: bad entry in directory: rec_len is smaller than minimal -
offset=0(0), inode=0, rec_len=0, name_len=0

... where 'debugfs -R "stat <172235804>" /dev/sdb1' reports that the
inode has block number 688923213.  When viewed in hex, block number
152052301 (from the syslog) is 0x910224D, while block number 688923213
is 0x2910224D.  Note the missing "0x20000000" in the block number.

Reported-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Verified-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Reported-by: Dave Jones <davej@redhat.com>
Verified-by: Dave Jones <davej@redhat.com>
Cc: Zheng Liu <gnehzuil.liu@gmail.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
fs/ext4/extents_status.h

index cf83e77..f190dfe 100644 (file)
 #define es_debug(fmt, ...)     no_printk(fmt, ##__VA_ARGS__)
 #endif
 
-#define EXTENT_STATUS_WRITTEN  0x80000000      /* written extent */
-#define EXTENT_STATUS_UNWRITTEN        0x40000000      /* unwritten extent */
-#define EXTENT_STATUS_DELAYED  0x20000000      /* delayed extent */
-#define EXTENT_STATUS_HOLE     0x10000000      /* hole */
+/*
+ * These flags live in the high bits of extent_status.es_pblk
+ */
+#define EXTENT_STATUS_WRITTEN  (1ULL << 63)
+#define EXTENT_STATUS_UNWRITTEN (1ULL << 62)
+#define EXTENT_STATUS_DELAYED  (1ULL << 61)
+#define EXTENT_STATUS_HOLE     (1ULL << 60)
 
 #define EXTENT_STATUS_FLAGS    (EXTENT_STATUS_WRITTEN | \
                                 EXTENT_STATUS_UNWRITTEN | \
@@ -58,22 +61,22 @@ extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
 
 static inline int ext4_es_is_written(struct extent_status *es)
 {
-       return (es->es_pblk & EXTENT_STATUS_WRITTEN);
+       return (es->es_pblk & EXTENT_STATUS_WRITTEN) != 0;
 }
 
 static inline int ext4_es_is_unwritten(struct extent_status *es)
 {
-       return (es->es_pblk & EXTENT_STATUS_UNWRITTEN);
+       return (es->es_pblk & EXTENT_STATUS_UNWRITTEN) != 0;
 }
 
 static inline int ext4_es_is_delayed(struct extent_status *es)
 {
-       return (es->es_pblk & EXTENT_STATUS_DELAYED);
+       return (es->es_pblk & EXTENT_STATUS_DELAYED) != 0;
 }
 
 static inline int ext4_es_is_hole(struct extent_status *es)
 {
-       return (es->es_pblk & EXTENT_STATUS_HOLE);
+       return (es->es_pblk & EXTENT_STATUS_HOLE) != 0;
 }
 
 static inline ext4_fsblk_t ext4_es_status(struct extent_status *es)