Fix patch formatting.
[ext4-patch-queue.git] / ext4_ext_get_blocks_fixes_for_preallocation.patch
blobef7682cc37f1e0cb01ed07a3208cd1d5b98b77c6
1 ext4: ext4_get_blocks_wrap() fix for wrting to preallocated
3 From: Mingming Cao <cmm@us.ibm.com>
5 This patch fixed a issue with wrting to a preallocated blocks.
6 A write hit a BUG_ON() in fs/buffer.c saying the buffer is not mapped.
8 On the write path, ext4_get_block_wrap() is called with create=1, but it
9 will pass create=0 down to the underlying ext4ext_get_blocks()
10 to do a look up first. In the preallocation case, ext4_ext_get_blocks()
11 with create = 0, will return number of blocks pre-allocated and buffer
12 head unmapped. ext4_get_blocks_wrap() thinks it succeeds too early, without
13 checking if it needs again call ext4_ext_get_blocks with create = 1
14 which would split the extent to initialized and uninitialized one and
15 returns the mapped buffer head.
17 Treating preallocated blocks as holes equally
18 (i.e. ignoring the number of blocks pre-allocated and returns 0)
19 when get_blocks() with create = 0 is not enough.
20 ext4_ext_get_blocks() needs to differentiate these two casesfor delayed
21 allocation purpose, as for holes it need to do reservation and prepare for later
22 delayed allocation, but for pre-allocated blocks it needs skip that work.
24 It would makes things more clear if we have clear definition of what
25 get_blocks() return value means.
27 Similar to ext4_get_blocks_handle(), the following
28 * return > 0, # of blocks already allocated
29 * if these are pre-allocated blocks and create = 0
30 * buffer head is unmapped
31 * otherwise blocks are mapped.
33 * return = 0, if plain look up failed (blocks have not been allocated)
34 * buffer head is unmapped
36 * return < 0, error case.
38 The for the write path, at ext4_ext_get_blocks_wrap(), it could check the
39 buffer_mapped() status for preallocated extent before quit too early.
41 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
43 ---
44 fs/ext4/extents.c | 13 +++++++++++++
45 fs/ext4/inode.c | 44 +++++++++++++++++++++++++++++++++++++++++---
46 2 files changed, 54 insertions(+), 3 deletions(-)
48 Index: linux-2.6.25-rc2/fs/ext4/extents.c
49 ===================================================================
50 --- linux-2.6.25-rc2.orig/fs/ext4/extents.c 2008-02-18 20:52:38.000000000 -0800
51 +++ linux-2.6.25-rc2/fs/ext4/extents.c 2008-02-19 00:02:46.000000000 -0800
52 @@ -2287,9 +2287,22 @@ out:
56 + * Block allocation/map/preallocation routine for extents based files
57 + *
58 + *
59 * Need to be called with
60 * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
61 * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
62 + *
63 + * return > 0, number of of blocks already mapped/allocated
64 + * if create == 0 and these are pre-allocated blocks
65 + * buffer head is unmapped
66 + * otherwise blocks are mapped
67 + *
68 + * return = 0, if plain look up failed (blocks have not been allocated)
69 + * buffer head is unmapped
70 + *
71 + * return < 0, error case.
73 int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
74 ext4_lblk_t iblock,
75 Index: linux-2.6.25-rc2/fs/ext4/inode.c
76 ===================================================================
77 --- linux-2.6.25-rc2.orig/fs/ext4/inode.c 2008-02-18 20:52:32.000000000 -0800
78 +++ linux-2.6.25-rc2/fs/ext4/inode.c 2008-02-19 00:03:20.000000000 -0800
79 @@ -908,11 +908,34 @@ out:
81 #define DIO_CREDITS 25
84 +/*
85 + * ext4 get_block() wrapper function
86 + * It first do a look up, returns if the blocks already mapped. Otherwise
87 + * it takes the write sem and do block allocation
88 + *
89 + * If file type is extents based, call with ext4_ext_get_blocks()
90 + * Otherwise, call with ext4_get_blocks_handle() to handle indirect mapping
91 + * based files
92 + *
93 + * return > 0, number of of blocks already mapped/allocated
94 + * if create==0 and these are pre-allocated blocks
95 + * buffer head is unmapped
96 + * otherwise blocks are mapped
97 + *
98 + * return = 0, if plain look up failed (blocks have not been allocated)
99 + * buffer head is unmapped
101 + * return < 0, error case.
102 + */
103 int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
104 unsigned long max_blocks, struct buffer_head *bh,
105 int create, int extend_disksize)
107 int retval;
109 + clear_buffer_mapped(bh);
112 * Try to see if we can get the block without requesting
113 * for new file system block.
114 @@ -926,12 +949,27 @@ int ext4_get_blocks_wrap(handle_t *handl
115 inode, block, max_blocks, bh, 0, 0);
117 up_read((&EXT4_I(inode)->i_data_sem));
118 - if (!create || (retval > 0))
120 + /* If it is only a block(s) look up */
121 + if (!create)
122 + return retval;
124 + /*
125 + * Returns if the blocks have already allocated
127 + * Note that if blocks have been preallocated
128 + * ext4_ext_get_block() returns with buffer head unmapped.
129 + * Write to a preallocated space needs to split
130 + * the preallocated extents, thus needs to update
131 + * i_data
132 + */
133 + if (retval > 0 && buffer_mapped(bh))
134 return retval;
137 - * We need to allocate new blocks which will result
138 - * in i_data update
139 + * New blocks and preallocation handling will possiblely result
140 + * in i_data update, take the write sem, and call get_blocks()
141 + * with create = 1
143 down_write((&EXT4_I(inode)->i_data_sem));