ext4: Add BUG_ON debugging checks to noalloc_get_block_write()
[safe/jmp/linux-2.6] / fs / ext4 / inode.c
index f758e80..e6113c3 100644 (file)
@@ -892,6 +892,10 @@ err_out:
 }
 
 /*
+ * The ext4_ind_get_blocks() function handles non-extents inodes
+ * (i.e., using the traditional indirect/double-indirect i_blocks
+ * scheme) for ext4_get_blocks().
+ *
  * Allocation strategy is simple: if we have to allocate something, we will
  * have to go the whole way to leaf. So let's do it before attaching anything
  * to tree, set linkage between the newborn blocks, write them if sync is
@@ -909,15 +913,16 @@ err_out:
  * return = 0, if plain lookup failed.
  * return < 0, error case.
  *
- *
- * Need to be called with
- * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
- * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
+ * The ext4_ind_get_blocks() function should be called with
+ * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
+ * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
+ * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
+ * blocks.
  */
 static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
                                  ext4_lblk_t iblock, unsigned int maxblocks,
                                  struct buffer_head *bh_result,
-                                 int create, int extend_disksize)
+                                 int flags)
 {
        int err = -EIO;
        ext4_lblk_t offsets[4];
@@ -934,7 +939,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
 
 
        J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
-       J_ASSERT(handle != NULL || create == 0);
+       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
        depth = ext4_block_to_path(inode, iblock, offsets,
                                        &blocks_to_boundary);
 
@@ -963,7 +968,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
        }
 
        /* Next simple case - plain lookup or failed read of indirect block */
-       if (!create || err == -EIO)
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
                goto cleanup;
 
        /*
@@ -1002,7 +1007,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
         * protect it if you're about to implement concurrent
         * ext4_get_block() -bzzz
        */
-       if (!err && extend_disksize) {
+       if (!err && (flags & EXT4_GET_BLOCKS_EXTEND_DISKSIZE)) {
                disksize = ((loff_t) iblock + count) << inode->i_blkbits;
                if (disksize > i_size_read(inode))
                        disksize = i_size_read(inode);
@@ -1121,7 +1126,7 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
 }
 
 /*
- * The ext4_get_blocks_wrap() function try to look up the requested blocks,
+ * The ext4_get_blocks() function tries to look up the requested blocks,
  * and returns if the blocks are already mapped.
  *
  * Otherwise it takes the write lock of the i_data_sem and allocate blocks
@@ -1142,9 +1147,9 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
  *
  * It returns the error in case of allocation failure.
  */
-int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
-                       unsigned int max_blocks, struct buffer_head *bh,
-                       int create, int extend_disksize, int flag)
+int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
+                   unsigned int max_blocks, struct buffer_head *bh,
+                   int flags)
 {
        int retval;
 
@@ -1152,21 +1157,21 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
        clear_buffer_unwritten(bh);
 
        /*
-        * Try to see if we can get  the block without requesting
-        * for new file system block.
+        * Try to see if we can get the block without requesting a new
+        * file system block.
         */
        down_read((&EXT4_I(inode)->i_data_sem));
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                               bh, 0, 0);
+                               bh, 0);
        } else {
                retval = ext4_ind_get_blocks(handle, inode, block, max_blocks,
-                                            bh, 0, 0);
+                                            bh, 0);
        }
        up_read((&EXT4_I(inode)->i_data_sem));
 
        /* If it is only a block(s) look up */
-       if (!create)
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)
                return retval;
 
        /*
@@ -1205,7 +1210,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
         * let the underlying get_block() function know to
         * avoid double accounting
         */
-       if (flag)
+       if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
                EXT4_I(inode)->i_delalloc_reserved_flag = 1;
        /*
         * We need to check for EXT4 here because migrate
@@ -1213,10 +1218,10 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
         */
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                               bh, create, extend_disksize);
+                                             bh, flags);
        } else {
                retval = ext4_ind_get_blocks(handle, inode, block,
-                               max_blocks, bh, create, extend_disksize);
+                                            max_blocks, bh, flags);
 
                if (retval > 0 && buffer_new(bh)) {
                        /*
@@ -1229,7 +1234,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                }
        }
 
-       if (flag) {
+       if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) {
                EXT4_I(inode)->i_delalloc_reserved_flag = 0;
                /*
                 * Update reserved blocks/metadata blocks
@@ -1268,8 +1273,8 @@ int ext4_get_block(struct inode *inode, sector_t iblock,
                started = 1;
        }
 
-       ret = ext4_get_blocks_wrap(handle, inode, iblock,
-                                       max_blocks, bh_result, create, 0, 0);
+       ret = ext4_get_blocks(handle, inode, iblock, max_blocks, bh_result,
+                             create ? EXT4_GET_BLOCKS_CREATE : 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -1288,17 +1293,19 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
 {
        struct buffer_head dummy;
        int fatal = 0, err;
+       int flags = EXT4_GET_BLOCKS_EXTEND_DISKSIZE;
 
        J_ASSERT(handle != NULL || create == 0);
 
        dummy.b_state = 0;
        dummy.b_blocknr = -1000;
        buffer_trace_init(&dummy.b_history);
-       err = ext4_get_blocks_wrap(handle, inode, block, 1,
-                                       &dummy, create, 1, 0);
+       if (create)
+               flags |= EXT4_GET_BLOCKS_CREATE;
+       err = ext4_get_blocks(handle, inode, block, 1, &dummy, flags);
        /*
-        * ext4_get_blocks_wrap() returns number of blocks
-        * mapped. 0 in case of a HOLE.
+        * ext4_get_blocks() returns number of blocks mapped. 0 in
+        * case of a HOLE.
         */
        if (err > 0) {
                if (err > 1)
@@ -1998,7 +2005,12 @@ static void ext4_print_free_blocks(struct inode *inode)
        return;
 }
 
-#define                EXT4_DELALLOC_RSVED     1
+/*
+ * This function is used by mpage_da_map_blocks().  We separate it out
+ * as a separate function just to make life easier, and because
+ * mpage_da_map_blocks() used to be a generic function that took a
+ * get_block_t.
+ */
 static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result)
 {
@@ -2009,8 +2021,9 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
 
        handle = ext4_journal_current_handle();
        BUG_ON(!handle);
-       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-                                  bh_result, 1, 0, EXT4_DELALLOC_RSVED);
+       ret = ext4_get_blocks(handle, inode, iblock, max_blocks,
+                             bh_result, EXT4_GET_BLOCKS_CREATE|
+                             EXT4_GET_BLOCKS_DELALLOC_RESERVE);
        if (ret <= 0)
                return ret;
 
@@ -2029,8 +2042,8 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
 
        /*
         * Update on-disk size along with block allocation we don't
-        * use 'extend_disksize' as size may change within already
-        * allocated block -bzzz
+        * use EXT4_GET_BLOCKS_EXTEND_DISKSIZE as size may change
+        * within already allocated block -bzzz
         */
        disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
        if (disksize > i_size_read(inode))
@@ -2066,16 +2079,17 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
                return 0;
        /*
         * We need to make sure the BH_Delay flag is passed down to
-        * ext4_da_get_block_write(), since it calls
-        * ext4_get_blocks_wrap() with the EXT4_DELALLOC_RSVED flag.
-        * This flag causes ext4_get_blocks_wrap() to call
+        * ext4_da_get_block_write(), since it calls ext4_get_blocks()
+        * with the EXT4_GET_BLOCKS_DELALLOC_RESERVE flag.  This flag
+        * causes ext4_get_blocks() to call
         * ext4_da_update_reserve_space() if the passed buffer head
         * has the BH_Delay flag set.  In the future, once we clean up
-        * the interfaces to ext4_get_blocks_wrap(), we should pass in
-        * separate flag which requests that the delayed allocation
+        * the interfaces to ext4_get_blocks(), we should pass in a
+        * separate flag which requests that the delayed allocation
         * statistics should be updated, instead of depending on the
         * state information getting passed down via the map_bh's
-        * state bitmasks plus the magic EXT4_DELALLOC_RSVED flag.
+        * state bitmasks plus the magic
+        * EXT4_GET_BLOCKS_DELALLOC_RESERVE flag.
         */
        new.b_state = mpd->b_state & (1 << BH_Delay);
        new.b_blocknr = 0;
@@ -2335,8 +2349,9 @@ static int __mpage_da_writepage(struct page *page,
 }
 
 /*
- * this is a special callback for ->write_begin() only
- * it's intention is to return mapped block or reserve space
+ * This is a special get_blocks_t callback which is used by
+ * ext4_da_write_begin().  It will either return mapped block or
+ * reserve space for a single block.
  *
  * For delayed buffer_head we have BH_Mapped, BH_New, BH_Delay set.
  * We also have b_blocknr = -1 and b_bdev initialized properly
@@ -2344,7 +2359,6 @@ static int __mpage_da_writepage(struct page *page,
  * For unwritten buffer_head we have BH_Mapped, BH_New, BH_Unwritten set.
  * We also have b_blocknr = physicalblock mapping unwritten extent and b_bdev
  * initialized properly.
- *
  */
 static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                                  struct buffer_head *bh_result, int create)
@@ -2363,7 +2377,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
         * preallocated blocks are unmapped but should treated
         * the same as allocated blocks.
         */
-       ret = ext4_get_blocks_wrap(NULL, inode, iblock, 1,  bh_result, 0, 0, 0);
+       ret = ext4_get_blocks(NULL, inode, iblock, 1,  bh_result, 0);
        if ((ret == 0) && !buffer_delay(bh_result)) {
                /* the block isn't (pre)allocated yet, let's reserve space */
                /*
@@ -2397,18 +2411,36 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
        return ret;
 }
 
-static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock,
+/*
+ * This function is used as a standard get_block_t calback function
+ * when there is no desire to allocate any blocks.  It is used as a
+ * callback function for block_prepare_write(), nobh_writepage(), and
+ * block_write_full_page().  These functions should only try to map a
+ * single block at a time.
+ *
+ * Since this function doesn't do block allocations even if the caller
+ * requests it by passing in create=1, it is critically important that
+ * any caller checks to make sure that any buffer heads are returned
+ * by this function are either all already mapped or marked for
+ * delayed allocation before calling nobh_writepage() or
+ * block_write_full_page().  Otherwise, b_blocknr could be left
+ * unitialized, and the page write functions will be taken by
+ * surprise.
+ */
+static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
 {
        int ret = 0;
        unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
 
+       BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
+
        /*
         * we don't want to do block allocation in writepage
         * so call get_block_wrap with create = 0
         */
-       ret = ext4_get_blocks_wrap(NULL, inode, iblock, max_blocks,
-                                  bh_result, 0, 0, 0);
+       ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0);
+       BUG_ON(create && ret == 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -2417,10 +2449,11 @@ static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock,
 }
 
 /*
- * get called vi ext4_da_writepages after taking page lock (have journal handle)
- * get called via journal_submit_inode_data_buffers (no journal handle)
- * get called via shrink_page_list via pdflush (no journal handle)
- * or grab_page_cache when doing write_begin (have journal handle)
+ * This function can get called via...
+ *   - ext4_da_writepages after taking page lock (have journal handle)
+ *   - journal_submit_inode_data_buffers (no journal handle)
+ *   - shrink_page_list via pdflush (no journal handle)
+ *   - grab_page_cache when doing write_begin (have journal handle)
  */
 static int ext4_da_writepage(struct page *page,
                                struct writeback_control *wbc)
@@ -2471,7 +2504,7 @@ static int ext4_da_writepage(struct page *page,
                 * do block allocation here.
                 */
                ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                               ext4_normal_get_block_write);
+                                         noalloc_get_block_write);
                if (!ret) {
                        page_bufs = page_buffers(page);
                        /* check whether all are mapped and non delay */
@@ -2496,11 +2529,10 @@ static int ext4_da_writepage(struct page *page,
        }
 
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
-               ret = nobh_writepage(page, ext4_normal_get_block_write, wbc);
+               ret = nobh_writepage(page, noalloc_get_block_write, wbc);
        else
-               ret = block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               ret = block_write_full_page(page, noalloc_get_block_write,
+                                           wbc);
 
        return ret;
 }
@@ -2812,7 +2844,7 @@ retry:
        *pagep = page;
 
        ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext4_da_get_block_prep);
+                               ext4_da_get_block_prep);
        if (ret < 0) {
                unlock_page(page);
                ext4_journal_stop(handle);
@@ -3120,12 +3152,10 @@ static int __ext4_normal_writepage(struct page *page,
        struct inode *inode = page->mapping->host;
 
        if (test_opt(inode->i_sb, NOBH))
-               return nobh_writepage(page,
-                                       ext4_normal_get_block_write, wbc);
+               return nobh_writepage(page, noalloc_get_block_write, wbc);
        else
-               return block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               return block_write_full_page(page, noalloc_get_block_write,
+                                            wbc);
 }
 
 static int ext4_normal_writepage(struct page *page,
@@ -3177,7 +3207,7 @@ static int __ext4_journalled_writepage(struct page *page,
        int err;
 
        ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                       ext4_normal_get_block_write);
+                                 noalloc_get_block_write);
        if (ret != 0)
                goto out_unlock;
 
@@ -3262,9 +3292,8 @@ static int ext4_journalled_writepage(struct page *page,
                 * really know unless we go poke around in the buffer_heads.
                 * But block_write_full_page will do the right thing.
                 */
-               return block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               return block_write_full_page(page, noalloc_get_block_write,
+                                            wbc);
        }
 no_write:
        redirty_page_for_writepage(wbc, page);
@@ -5034,7 +5063,7 @@ int ext4_writepage_trans_blocks(struct inode *inode)
  * Calculate the journal credits for a chunk of data modification.
  *
  * This is called from DIO, fallocate or whoever calling
- * ext4_get_blocks_wrap() to map/allocate a chunk of contigous disk blocks.
+ * ext4_get_blocks() to map/allocate a chunk of contigous disk blocks.
  *
  * journal buffers for data blocks are not included here, as DIO
  * and fallocate do no need to journal data buffers.