Pull platform-drivers into test branch
[pandora-kernel.git] / fs / ext4 / inode.c
index effc38a..a127cc0 100644 (file)
@@ -1147,37 +1147,102 @@ static int do_journal_get_write_access(handle_t *handle,
        return ext4_journal_get_write_access(handle, bh);
 }
 
+/*
+ * The idea of this helper function is following:
+ * if prepare_write has allocated some blocks, but not all of them, the
+ * transaction must include the content of the newly allocated blocks.
+ * This content is expected to be set to zeroes by block_prepare_write().
+ * 2006/10/14  SAW
+ */
+static int ext4_prepare_failure(struct file *file, struct page *page,
+                               unsigned from, unsigned to)
+{
+       struct address_space *mapping;
+       struct buffer_head *bh, *head, *next;
+       unsigned block_start, block_end;
+       unsigned blocksize;
+       int ret;
+       handle_t *handle = ext4_journal_current_handle();
+
+       mapping = page->mapping;
+       if (ext4_should_writeback_data(mapping->host)) {
+               /* optimization: no constraints about data */
+skip:
+               return ext4_journal_stop(handle);
+       }
+
+       head = page_buffers(page);
+       blocksize = head->b_size;
+       for (   bh = head, block_start = 0;
+               bh != head || !block_start;
+               block_start = block_end, bh = next)
+       {
+               next = bh->b_this_page;
+               block_end = block_start + blocksize;
+               if (block_end <= from)
+                       continue;
+               if (block_start >= to) {
+                       block_start = to;
+                       break;
+               }
+               if (!buffer_mapped(bh))
+               /* prepare_write failed on this bh */
+                       break;
+               if (ext4_should_journal_data(mapping->host)) {
+                       ret = do_journal_get_write_access(handle, bh);
+                       if (ret) {
+                               ext4_journal_stop(handle);
+                               return ret;
+                       }
+               }
+       /*
+        * block_start here becomes the first block where the current iteration
+        * of prepare_write failed.
+        */
+       }
+       if (block_start <= from)
+               goto skip;
+
+       /* commit allocated and zeroed buffers */
+       return mapping->a_ops->commit_write(file, page, from, block_start);
+}
+
 static int ext4_prepare_write(struct file *file, struct page *page,
                              unsigned from, unsigned to)
 {
        struct inode *inode = page->mapping->host;
-       int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
+       int ret, ret2;
+       int needed_blocks = ext4_writepage_trans_blocks(inode);
        handle_t *handle;
        int retries = 0;
 
 retry:
        handle = ext4_journal_start(inode, needed_blocks);
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               goto out;
-       }
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
                ret = nobh_prepare_write(page, from, to, ext4_get_block);
        else
                ret = block_prepare_write(page, from, to, ext4_get_block);
        if (ret)
-               goto prepare_write_failed;
+               goto failure;
 
        if (ext4_should_journal_data(inode)) {
                ret = walk_page_buffers(handle, page_buffers(page),
                                from, to, NULL, do_journal_get_write_access);
+               if (ret)
+                       /* fatal error, just put the handle and return */
+                       ext4_journal_stop(handle);
        }
-prepare_write_failed:
-       if (ret)
-               ext4_journal_stop(handle);
+       return ret;
+
+failure:
+       ret2 = ext4_prepare_failure(file, page, from, to);
+       if (ret2 < 0)
+               return ret2;
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
-out:
+       /* retry number exceeded, or other error like -EDQUOT */
        return ret;
 }
 
@@ -2115,7 +2180,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                         */
                        if (!bh) {
                                ext4_error(inode->i_sb, "ext4_free_branches",
-                                          "Read failure, inode=%lu, block="E3FSBLK,
+                                          "Read failure, inode=%lu, block=%llu",
                                           inode->i_ino, nr);
                                continue;
                        }
@@ -2432,14 +2497,15 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
                return 0;
        }
 
-       gdp = (struct ext4_group_desc *)bh->b_data;
+       gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
+               desc * EXT4_DESC_SIZE(sb));
        /*
         * Figure out the offset within the block group inode table
         */
        offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
                EXT4_INODE_SIZE(sb);
-       block = ext4_inode_table(gdp + desc) +
-                       (offset >> EXT4_BLOCK_SIZE_BITS(sb));
+       block = ext4_inode_table(sb, gdp) +
+               (offset >> EXT4_BLOCK_SIZE_BITS(sb));
 
        iloc->block_group = block_group;
        iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
@@ -2466,7 +2532,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
        if (!bh) {
                ext4_error (inode->i_sb, "ext4_get_inode_loc",
                                "unable to read inode block - "
-                               "inode=%lu, block="E3FSBLK,
+                               "inode=%lu, block=%llu",
                                 inode->i_ino, block);
                return -EIO;
        }
@@ -2506,7 +2572,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
                                goto make_io;
 
                        bitmap_bh = sb_getblk(inode->i_sb,
-                               ext4_inode_bitmap(desc));
+                               ext4_inode_bitmap(inode->i_sb, desc));
                        if (!bitmap_bh)
                                goto make_io;
 
@@ -2548,7 +2614,7 @@ make_io:
                if (!buffer_uptodate(bh)) {
                        ext4_error(inode->i_sb, "ext4_get_inode_loc",
                                        "unable to read inode block - "
-                                       "inode=%lu, block="E3FSBLK,
+                                       "inode=%lu, block=%llu",
                                        inode->i_ino, block);
                        brelse(bh);
                        return -EIO;
@@ -2643,9 +2709,8 @@ void ext4_read_inode(struct inode * inode)
        ei->i_frag_size = raw_inode->i_fsize;
 #endif
        ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
-       if ((sizeof(sector_t) > 4) &&
-           (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
-            cpu_to_le32(EXT4_OS_HURD)))
+       if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+           cpu_to_le32(EXT4_OS_HURD))
                ei->i_file_acl |=
                        ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
        if (!S_ISREG(inode->i_mode)) {
@@ -2781,9 +2846,8 @@ static int ext4_do_update_inode(handle_t *handle,
        raw_inode->i_frag = ei->i_frag_no;
        raw_inode->i_fsize = ei->i_frag_size;
 #endif
-       if ((sizeof(sector_t) > 4) &&
-           (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
-            cpu_to_le32(EXT4_OS_HURD)))
+       if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+           cpu_to_le32(EXT4_OS_HURD))
                raw_inode->i_file_acl_high =
                        cpu_to_le16(ei->i_file_acl >> 32);
        raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);