Merge branch 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux...
[sfrench/cifs-2.6.git] / fs / ext4 / inode.c
index 349dd6b4da47492ed2e8e94f613de6e1e86dd676..064746fad5812e693ef6d3ef2578822a3007cadb 100644 (file)
@@ -192,11 +192,24 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
  * so before we call here everything must be consistently dirtied against
  * this transaction.
  */
-static int ext4_journal_test_restart(handle_t *handle, struct inode *inode)
+ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
+                                int nblocks)
 {
+       int ret;
+
+       /*
+        * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this
+        * moment, get_block can be called only for blocks inside i_size since
+        * page cache has been already dropped and writes are blocked by
+        * i_mutex. So we can safely drop the i_data_sem here.
+        */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        jbd_debug(2, "restarting handle %p\n", handle);
-       return ext4_journal_restart(handle, blocks_for_truncate(inode));
+       up_write(&EXT4_I(inode)->i_data_sem);
+       ret = ext4_journal_restart(handle, blocks_for_truncate(inode));
+       down_write(&EXT4_I(inode)->i_data_sem);
+
+       return ret;
 }
 
 /*
@@ -341,9 +354,7 @@ static int ext4_block_to_path(struct inode *inode,
        int n = 0;
        int final = 0;
 
-       if (i_block < 0) {
-               ext4_warning(inode->i_sb, "ext4_block_to_path", "block < 0");
-       } else if (i_block < direct_blocks) {
+       if (i_block < direct_blocks) {
                offsets[n++] = i_block;
                final = direct_blocks;
        } else if ((i_block -= direct_blocks) < indirect_blocks) {
@@ -551,15 +562,21 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
  *
  *     Normally this function find the preferred place for block allocation,
  *     returns it.
+ *     Because this is only used for non-extent files, we limit the block nr
+ *     to 32 bits.
  */
 static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
                                   Indirect *partial)
 {
+       ext4_fsblk_t goal;
+
        /*
         * XXX need to get goal block from mballoc's data structures
         */
 
-       return ext4_find_near(inode, partial);
+       goal = ext4_find_near(inode, partial);
+       goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
+       return goal;
 }
 
 /**
@@ -640,6 +657,8 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
                if (*err)
                        goto failed_out;
 
+               BUG_ON(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS);
+
                target -= count;
                /* allocate blocks for indirect blocks */
                while (index < indirect_blks && count) {
@@ -674,6 +693,7 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
                ar.flags = EXT4_MB_HINT_DATA;
 
        current_block = ext4_mb_new_blocks(handle, &ar, err);
+       BUG_ON(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS);
 
        if (*err && (target == blks)) {
                /*
@@ -762,8 +782,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
                BUFFER_TRACE(bh, "call get_create_access");
                err = ext4_journal_get_create_access(handle, bh);
                if (err) {
+                       /* Don't brelse(bh) here; it's done in
+                        * ext4_journal_forget() below */
                        unlock_buffer(bh);
-                       brelse(bh);
                        goto failed;
                }
 
@@ -1109,16 +1130,15 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
                ext4_discard_preallocations(inode);
 }
 
-static int check_block_validity(struct inode *inode, sector_t logical,
-                               sector_t phys, int len)
+static int check_block_validity(struct inode *inode, const char *msg,
+                               sector_t logical, sector_t phys, int len)
 {
        if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) {
-               ext4_error(inode->i_sb, "check_block_validity",
+               ext4_error(inode->i_sb, msg,
                           "inode #%lu logical block %llu mapped to %llu "
                           "(size %d)", inode->i_ino,
                           (unsigned long long) logical,
                           (unsigned long long) phys, len);
-               WARN_ON(1);
                return -EIO;
        }
        return 0;
@@ -1170,8 +1190,8 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
        up_read((&EXT4_I(inode)->i_data_sem));
 
        if (retval > 0 && buffer_mapped(bh)) {
-               int ret = check_block_validity(inode, block,
-                                              bh->b_blocknr, retval);
+               int ret = check_block_validity(inode, "file system corruption",
+                                              block, bh->b_blocknr, retval);
                if (ret != 0)
                        return ret;
        }
@@ -1235,8 +1255,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
                         * i_data's format changing.  Force the migrate
                         * to fail by clearing migrate flags
                         */
-                       EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
-                                                       ~EXT4_EXT_MIGRATE;
+                       EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE;
                }
        }
 
@@ -1252,8 +1271,9 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
 
        up_write((&EXT4_I(inode)->i_data_sem));
        if (retval > 0 && buffer_mapped(bh)) {
-               int ret = check_block_validity(inode, block,
-                                              bh->b_blocknr, retval);
+               int ret = check_block_validity(inode, "file system "
+                                              "corruption after allocation",
+                                              block, bh->b_blocknr, retval);
                if (ret != 0)
                        return ret;
        }
@@ -1863,18 +1883,6 @@ static void ext4_da_page_release_reservation(struct page *page,
  * Delayed allocation stuff
  */
 
-struct mpage_da_data {
-       struct inode *inode;
-       sector_t b_blocknr;             /* start block number of extent */
-       size_t b_size;                  /* size of extent */
-       unsigned long b_state;          /* state of the extent */
-       unsigned long first_page, next_page;    /* extent of pages */
-       struct writeback_control *wbc;
-       int io_done;
-       int pages_written;
-       int retval;
-};
-
 /*
  * mpage_da_submit_io - walks through extent of pages and try to write
  * them with writepage() call back
@@ -2329,7 +2337,7 @@ static int __mpage_da_writepage(struct page *page,
                /*
                 * Rest of the page in the page_vec
                 * redirty then and skip then. We will
-                * try to to write them again after
+                * try to write them again after
                 * starting a new transaction
                 */
                redirty_page_for_writepage(wbc, page);
@@ -2737,6 +2745,7 @@ static int ext4_da_writepages(struct address_space *mapping,
        long pages_skipped;
        int range_cyclic, cycled = 1, io_done = 0;
        int needed_blocks, ret = 0, nr_to_writebump = 0;
+       loff_t range_start = wbc->range_start;
        struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
 
        trace_ext4_da_writepages(inode, wbc);
@@ -2850,6 +2859,7 @@ retry:
                        mpd.io_done = 1;
                        ret = MPAGE_DA_EXTENT_TAIL;
                }
+               trace_ext4_da_write_pages(inode, &mpd);
                wbc->nr_to_write -= mpd.pages_written;
 
                ext4_journal_stop(handle);
@@ -2905,6 +2915,7 @@ out_writepages:
        if (!no_nrwrite_index_update)
                wbc->no_nrwrite_index_update = 0;
        wbc->nr_to_write -= nr_to_writebump;
+       wbc->range_start = range_start;
        trace_ext4_da_writepages_result(inode, wbc, ret, pages_written);
        return ret;
 }
@@ -3117,6 +3128,8 @@ out:
  */
 int ext4_alloc_da_blocks(struct inode *inode)
 {
+       trace_ext4_alloc_da_blocks(inode);
+
        if (!EXT4_I(inode)->i_reserved_data_blocks &&
            !EXT4_I(inode)->i_reserved_meta_blocks)
                return 0;
@@ -3663,7 +3676,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
                        ext4_handle_dirty_metadata(handle, inode, bh);
                }
                ext4_mark_inode_dirty(handle, inode);
-               ext4_journal_test_restart(handle, inode);
+               ext4_truncate_restart_trans(handle, inode,
+                                           blocks_for_truncate(inode));
                if (bh) {
                        BUFFER_TRACE(bh, "retaking write access");
                        ext4_journal_get_write_access(handle, bh);
@@ -3874,7 +3888,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                                return;
                        if (try_to_extend_transaction(handle, inode)) {
                                ext4_mark_inode_dirty(handle, inode);
-                               ext4_journal_test_restart(handle, inode);
+                               ext4_truncate_restart_trans(handle, inode,
+                                           blocks_for_truncate(inode));
                        }
 
                        ext4_free_blocks(handle, inode, nr, 1, 1);
@@ -3962,8 +3977,7 @@ void ext4_truncate(struct inode *inode)
        if (!ext4_can_truncate(inode))
                return;
 
-       if (ei->i_disksize && inode->i_size == 0 &&
-           !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
+       if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
                ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE;
 
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
@@ -4537,7 +4551,8 @@ static int ext4_inode_blocks_set(handle_t *handle,
  */
 static int ext4_do_update_inode(handle_t *handle,
                                struct inode *inode,
-                               struct ext4_iloc *iloc)
+                               struct ext4_iloc *iloc,
+                               int do_sync)
 {
        struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
        struct ext4_inode_info *ei = EXT4_I(inode);
@@ -4585,8 +4600,7 @@ static int ext4_do_update_inode(handle_t *handle,
        if (ext4_inode_blocks_set(handle, raw_inode, ei))
                goto out_brelse;
        raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
-       /* clear the migrate flag in the raw_inode */
-       raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE);
+       raw_inode->i_flags = cpu_to_le32(ei->i_flags);
        if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
            cpu_to_le32(EXT4_OS_HURD))
                raw_inode->i_file_acl_high =
@@ -4639,10 +4653,22 @@ static int ext4_do_update_inode(handle_t *handle,
                raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
        }
 
-       BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-       rc = ext4_handle_dirty_metadata(handle, inode, bh);
-       if (!err)
-               err = rc;
+       /*
+        * If we're not using a journal and we were called from
+        * ext4_write_inode() to sync the inode (making do_sync true),
+        * we can just use sync_dirty_buffer() directly to do our dirty
+        * work.  Testing s_journal here is a bit redundant but it's
+        * worth it to avoid potential future trouble.
+        */
+       if (EXT4_SB(inode->i_sb)->s_journal == NULL && do_sync) {
+               BUFFER_TRACE(bh, "call sync_dirty_buffer");
+               sync_dirty_buffer(bh);
+       } else {
+               BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
+               rc = ext4_handle_dirty_metadata(handle, inode, bh);
+               if (!err)
+                       err = rc;
+       }
        ei->i_state &= ~EXT4_STATE_NEW;
 
 out_brelse:
@@ -4688,19 +4714,32 @@ out_brelse:
  */
 int ext4_write_inode(struct inode *inode, int wait)
 {
+       int err;
+
        if (current->flags & PF_MEMALLOC)
                return 0;
 
-       if (ext4_journal_current_handle()) {
-               jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n");
-               dump_stack();
-               return -EIO;
-       }
+       if (EXT4_SB(inode->i_sb)->s_journal) {
+               if (ext4_journal_current_handle()) {
+                       jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n");
+                       dump_stack();
+                       return -EIO;
+               }
 
-       if (!wait)
-               return 0;
+               if (!wait)
+                       return 0;
+
+               err = ext4_force_commit(inode->i_sb);
+       } else {
+               struct ext4_iloc iloc;
 
-       return ext4_force_commit(inode->i_sb);
+               err = ext4_get_inode_loc(inode, &iloc);
+               if (err)
+                       return err;
+               err = ext4_do_update_inode(EXT4_NOJOURNAL_HANDLE,
+                                          inode, &iloc, wait);
+       }
+       return err;
 }
 
 /*
@@ -4994,7 +5033,7 @@ int ext4_mark_iloc_dirty(handle_t *handle,
        get_bh(iloc->bh);
 
        /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */
-       err = ext4_do_update_inode(handle, inode, iloc);
+       err = ext4_do_update_inode(handle, inode, iloc, 0);
        put_bh(iloc->bh);
        return err;
 }
@@ -5285,12 +5324,21 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        else
                len = PAGE_CACHE_SIZE;
 
+       lock_page(page);
+       /*
+        * return if we have all the buffers mapped. This avoid
+        * the need to call write_begin/write_end which does a
+        * journal_start/journal_stop which can block and take
+        * long time
+        */
        if (page_has_buffers(page)) {
-               /* return if we have all the buffers mapped */
                if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
-                                      ext4_bh_unmapped))
+                                       ext4_bh_unmapped)) {
+                       unlock_page(page);
                        goto out_unlock;
+               }
        }
+       unlock_page(page);
        /*
         * OK, we need to fill the hole... Do write_begin write_end
         * to do block allocation/reservation.We are not holding