rk312x: add psci support
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / inode.c
index e48bd5a1814b72dbf751b1d4390a0bae167e4cb6..27f5b47968ca41039a6fbdbcd609c1c766c02521 100644 (file)
@@ -626,6 +626,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@ -736,6 +737,7 @@ found:
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@ -1030,7 +1032,8 @@ retry_journal:
                ext4_journal_stop(handle);
                goto retry_grab;
        }
-       wait_on_page_writeback(page);
+       /* In case writeback began while the page was unlocked */
+       wait_for_stable_page(page);
 
        if (ext4_should_dioread_nolock(inode))
                ret = __block_write_begin(page, pos, len, ext4_get_block_write);
@@ -1409,7 +1412,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
 static void ext4_da_page_release_reservation(struct page *page,
                                             unsigned long offset)
 {
-       int to_release = 0;
+       int to_release = 0, contiguous_blks = 0;
        struct buffer_head *head, *bh;
        unsigned int curr_off = 0;
        struct inode *inode = page->mapping->host;
@@ -1424,14 +1427,23 @@ static void ext4_da_page_release_reservation(struct page *page,
 
                if ((offset <= curr_off) && (buffer_delay(bh))) {
                        to_release++;
+                       contiguous_blks++;
                        clear_buffer_delay(bh);
+               } else if (contiguous_blks) {
+                       lblk = page->index <<
+                              (PAGE_CACHE_SHIFT - inode->i_blkbits);
+                       lblk += (curr_off >> inode->i_blkbits) -
+                               contiguous_blks;
+                       ext4_es_remove_extent(inode, lblk, contiguous_blks);
+                       contiguous_blks = 0;
                }
                curr_off = next_off;
        } while ((bh = bh->b_this_page) != head);
 
-       if (to_release) {
+       if (contiguous_blks) {
                lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-               ext4_es_remove_extent(inode, lblk, to_release);
+               lblk += (curr_off >> inode->i_blkbits) - contiguous_blks;
+               ext4_es_remove_extent(inode, lblk, contiguous_blks);
        }
 
        /* If we have released all the blocks belonging to a cluster, then we
@@ -2096,19 +2108,32 @@ static int __ext4_journalled_writepage(struct page *page,
                ext4_walk_page_buffers(handle, page_bufs, 0, len,
                                       NULL, bget_one);
        }
-       /* As soon as we unlock the page, it can go away, but we have
-        * references to buffers so we are safe */
+       /*
+        * We need to release the page lock before we start the
+        * journal, so grab a reference so the page won't disappear
+        * out from under us.
+        */
+       get_page(page);
        unlock_page(page);
 
        handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
                                    ext4_writepage_trans_blocks(inode));
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
-               goto out;
+               put_page(page);
+               goto out_no_pagelock;
        }
-
        BUG_ON(!ext4_handle_valid(handle));
 
+       lock_page(page);
+       put_page(page);
+       if (page->mapping != mapping) {
+               /* The page got truncated from under us */
+               ext4_journal_stop(handle);
+               ret = 0;
+               goto out;
+       }
+
        if (inline_data) {
                ret = ext4_journal_get_write_access(handle, inode_bh);
 
@@ -2133,6 +2158,8 @@ static int __ext4_journalled_writepage(struct page *page,
                                       NULL, bput_one);
        ext4_set_inode_state(inode, EXT4_STATE_JDATA);
 out:
+       unlock_page(page);
+out_no_pagelock:
        brelse(inode_bh);
        return ret;
 }
@@ -2727,7 +2754,7 @@ retry_journal:
                goto retry_grab;
        }
        /* In case writeback began while the page was unlocked */
-       wait_on_page_writeback(page);
+       wait_for_stable_page(page);
 
        ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
        if (ret < 0) {
@@ -3089,7 +3116,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
        if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
                ext4_free_io_end(io_end);
 out:
-               inode_dio_done(inode);
+               inode_dio_end(inode);
                if (is_async)
                        aio_complete(iocb, ret, 0);
                return;
@@ -3147,7 +3174,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
        overwrite = *((int *)iocb->private);
 
        if (overwrite) {
-               atomic_inc(&inode->i_dio_count);
+               inode_dio_begin(inode);
                down_read(&EXT4_I(inode)->i_data_sem);
                mutex_unlock(&inode->i_mutex);
        }
@@ -3240,7 +3267,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
 retake_lock:
        /* take i_mutex locking again if we do a ovewrite dio */
        if (overwrite) {
-               inode_dio_done(inode);
+               inode_dio_end(inode);
                up_read(&EXT4_I(inode)->i_data_sem);
                mutex_lock(&inode->i_mutex);
        }