]> err.no Git - linux-2.6/blobdiff - fs/ext4/extents.c
reiserfs: convert j_commit_lock to mutex
[linux-2.6] / fs / ext4 / extents.c
index 555155d239df54a08edbd15690ed04c581ed4ad7..42c4c0c892ed9b442617207b00acbdc7be99249f 100644 (file)
@@ -248,6 +248,36 @@ static int ext4_ext_space_root_idx(struct inode *inode)
        return size;
 }
 
+/*
+ * Calculate the number of metadata blocks needed
+ * to allocate @blocks
+ * Worse case is one block per extent
+ */
+int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks)
+{
+       int lcap, icap, rcap, leafs, idxs, num;
+       int newextents = blocks;
+
+       rcap = ext4_ext_space_root_idx(inode);
+       lcap = ext4_ext_space_block(inode);
+       icap = ext4_ext_space_block_idx(inode);
+
+       /* number of new leaf blocks needed */
+       num = leafs = (newextents + lcap - 1) / lcap;
+
+       /*
+        * Worse case, we need separate index block(s)
+        * to link all new leaf blocks
+        */
+       idxs = (leafs + icap - 1) / icap;
+       do {
+               num += idxs;
+               idxs = (idxs + icap - 1) / icap;
+       } while (idxs > rcap);
+
+       return num;
+}
+
 static int
 ext4_ext_max_entries(struct inode *inode, int depth)
 {
@@ -2535,6 +2565,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        int err = 0, depth, ret;
        unsigned long allocated = 0;
        struct ext4_allocation_request ar;
+       loff_t disksize;
 
        __clear_bit(BH_New, &bh_result->b_state);
        ext_debug("blocks %u/%lu requested for inode %u\n",
@@ -2622,8 +2653,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                 */
                                if (allocated > max_blocks)
                                        allocated = max_blocks;
-                               /* mark the buffer unwritten */
-                               __set_bit(BH_Unwritten, &bh_result->b_state);
+                               set_buffer_unwritten(bh_result);
                                goto out2;
                        }
 
@@ -2726,10 +2756,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        newblock = ext_pblock(&newex);
        allocated = ext4_ext_get_actual_len(&newex);
 outnew:
-       if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize)
-               EXT4_I(inode)->i_disksize = inode->i_size;
+       if (extend_disksize) {
+               disksize = ((loff_t) iblock + ar.len) << inode->i_blkbits;
+               if (disksize > i_size_read(inode))
+                       disksize = i_size_read(inode);
+               if (disksize > EXT4_I(inode)->i_disksize)
+                       EXT4_I(inode)->i_disksize = disksize;
+       }
 
-       __set_bit(BH_New, &bh_result->b_state);
+       set_buffer_new(bh_result);
 
        /* Cache only when it is _not_ an uninitialized extent */
        if (create != EXT4_CREATE_UNINITIALIZED_EXT)
@@ -2739,7 +2774,7 @@ out:
        if (allocated > max_blocks)
                allocated = max_blocks;
        ext4_ext_show_leaf(inode, path);
-       __set_bit(BH_Mapped, &bh_result->b_state);
+       set_buffer_mapped(bh_result);
        bh_result->b_bdev = inode->i_sb->s_bdev;
        bh_result->b_blocknr = newblock;
 out2:
@@ -2750,7 +2785,7 @@ out2:
        return err ? err : allocated;
 }
 
-void ext4_ext_truncate(struct inode * inode, struct page *page)
+void ext4_ext_truncate(struct inode *inode)
 {
        struct address_space *mapping = inode->i_mapping;
        struct super_block *sb = inode->i_sb;
@@ -2763,18 +2798,14 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
         */
        err = ext4_writepage_trans_blocks(inode) + 3;
        handle = ext4_journal_start(inode, err);
-       if (IS_ERR(handle)) {
-               if (page) {
-                       clear_highpage(page);
-                       flush_dcache_page(page);
-                       unlock_page(page);
-                       page_cache_release(page);
-               }
+       if (IS_ERR(handle))
                return;
-       }
 
-       if (page)
-               ext4_block_truncate_page(handle, page, mapping, inode->i_size);
+       if (inode->i_size & (sb->s_blocksize - 1))
+               ext4_block_truncate_page(handle, mapping, inode->i_size);
+
+       if (ext4_orphan_add(handle, inode))
+               goto out_stop;
 
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_ext_invalidate_cache(inode);
@@ -2786,8 +2817,6 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
         * Probably we need not scan at all,
         * because page truncation is enough.
         */
-       if (ext4_orphan_add(handle, inode))
-               goto out_stop;
 
        /* we have to know where to truncate from in crash case */
        EXT4_I(inode)->i_disksize = inode->i_size;
@@ -2804,6 +2833,7 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
                handle->h_sync = 1;
 
 out_stop:
+       up_write(&EXT4_I(inode)->i_data_sem);
        /*
         * If this was a simple ftruncate() and the file will remain alive,
         * then we need to clear up the orphan record which we created above.
@@ -2814,7 +2844,6 @@ out_stop:
        if (inode->i_nlink)
                ext4_orphan_del(handle, inode);
 
-       up_write(&EXT4_I(inode)->i_data_sem);
        inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
        ext4_journal_stop(handle);
@@ -2917,7 +2946,7 @@ retry:
                }
                ret = ext4_get_blocks_wrap(handle, inode, block,
                                          max_blocks, &map_bh,
-                                         EXT4_CREATE_UNINITIALIZED_EXT, 0);
+                                         EXT4_CREATE_UNINITIALIZED_EXT, 0, 0);
                if (ret <= 0) {
 #ifdef EXT4FS_DEBUG
                        WARN_ON(ret <= 0);