Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=749269facaf87f6e516c3af12763e03181b9c139
Commit:     749269facaf87f6e516c3af12763e03181b9c139
Parent:     56055d3ae4cc7fa6d2b10885f20269de8a989ed7
Author:     Amit Arora <[EMAIL PROTECTED]>
AuthorDate: Wed Jul 18 09:02:56 2007 -0400
Committer:  Theodore Ts'o <[EMAIL PROTECTED]>
CommitDate: Wed Jul 18 09:02:56 2007 -0400

    Change on-disk format to support 2^15 uninitialized extents
    
    This change was suggested by Andreas Dilger.
    This patch changes the EXT_MAX_LEN value and extent code which marks/checks
    uninitialized extents. With this change it will be possible to have
    initialized extents with 2^15 blocks (earlier the max blocks we could have
    was 2^15 - 1). This way we can have better extent-to-block alignment.
    Now, maximum number of blocks we can have in an initialized extent is 2^15
    and in an uninitialized extent is 2^15 - 1.
    
    Signed-off-by: Amit Arora <[EMAIL PROTECTED]>
---
 fs/ext4/extents.c               |   28 +++++++++++++++++++++++++---
 include/linux/ext4_fs_extents.h |   31 +++++++++++++++++++++++++++----
 2 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ded3d46..77146b8 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1107,7 +1107,7 @@ static int
 ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
                                struct ext4_extent *ex2)
 {
-       unsigned short ext1_ee_len, ext2_ee_len;
+       unsigned short ext1_ee_len, ext2_ee_len, max_len;
 
        /*
         * Make sure that either both extents are uninitialized, or
@@ -1116,6 +1116,11 @@ ext4_can_extents_be_merged(struct inode *inode, struct 
ext4_extent *ex1,
        if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))
                return 0;
 
+       if (ext4_ext_is_uninitialized(ex1))
+               max_len = EXT_UNINIT_MAX_LEN;
+       else
+               max_len = EXT_INIT_MAX_LEN;
+
        ext1_ee_len = ext4_ext_get_actual_len(ex1);
        ext2_ee_len = ext4_ext_get_actual_len(ex2);
 
@@ -1128,7 +1133,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct 
ext4_extent *ex1,
         * as an RO_COMPAT feature, refuse to merge to extents if
         * this can result in the top bit of ee_len being set.
         */
-       if (ext1_ee_len + ext2_ee_len > EXT_MAX_LEN)
+       if (ext1_ee_len + ext2_ee_len > max_len)
                return 0;
 #ifdef AGGRESSIVE_TEST
        if (le16_to_cpu(ex1->ee_len) >= 4)
@@ -1815,7 +1820,11 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
 
                ex->ee_block = cpu_to_le32(block);
                ex->ee_len = cpu_to_le16(num);
-               if (uninitialized)
+               /*
+                * Do not mark uninitialized if all the blocks in the
+                * extent have been removed.
+                */
+               if (uninitialized && num)
                        ext4_ext_mark_uninitialized(ex);
 
                err = ext4_ext_dirty(handle, inode, path + depth);
@@ -2308,6 +2317,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode 
*inode,
        /* allocate new block */
        goal = ext4_ext_find_goal(inode, path, iblock);
 
+       /*
+        * See if request is beyond maximum number of blocks we can have in
+        * a single extent. For an initialized extent this limit is
+        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+        * EXT_UNINIT_MAX_LEN.
+        */
+       if (max_blocks > EXT_INIT_MAX_LEN &&
+           create != EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_INIT_MAX_LEN;
+       else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+                create == EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_UNINIT_MAX_LEN;
+
        /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
        newex.ee_block = cpu_to_le32(iblock);
        newex.ee_len = cpu_to_le16(max_blocks);
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h
index edf49ec..81406f3 100644
--- a/include/linux/ext4_fs_extents.h
+++ b/include/linux/ext4_fs_extents.h
@@ -141,7 +141,25 @@ typedef int (*ext_prepare_callback)(struct inode *, struct 
ext4_ext_path *,
 
 #define EXT_MAX_BLOCK  0xffffffff
 
-#define EXT_MAX_LEN    ((1UL << 15) - 1)
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN       (1UL << 15)
+#define EXT_UNINIT_MAX_LEN     (EXT_INIT_MAX_LEN - 1)
 
 
 #define EXT_FIRST_EXTENT(__hdr__) \
@@ -190,17 +208,22 @@ ext4_ext_invalidate_cache(struct inode *inode)
 
 static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
 {
-       ext->ee_len |= cpu_to_le16(0x8000);
+       /* We can not have an uninitialized extent of zero length! */
+       BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
+       ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
 }
 
 static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
 {
-       return (int)(le16_to_cpu((ext)->ee_len) & 0x8000);
+       /* Extent with ee_len of 0x8000 is treated as an initialized extent */
+       return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
 }
 
 static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
 {
-       return (int)(le16_to_cpu((ext)->ee_len) & 0x7FFF);
+       return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
+               le16_to_cpu(ext->ee_len) :
+               (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
 }
 
 extern int ext4_extent_tree_init(handle_t *, struct inode *);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to